Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/emfio/source/reader/emfreader.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
#include <basegfx/polygon/b2dpolygontools.hxx>
20
#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
21
#include <emfreader.hxx>
22
#include <rtl/ustrbuf.hxx>
23
#include <sal/log.hxx>
24
#include <osl/diagnose.h>
25
#include <vcl/dibtools.hxx>
26
#include <o3tl/environment.hxx>
27
#include <o3tl/safeint.hxx>
28
#include <o3tl/sprintf.hxx>
29
#include <tools/stream.hxx>
30
#include <memory>
31
#include <comphelper/configuration.hxx>
32
#include <vcl/alpha.hxx>
33
#include <vcl/graph.hxx>
34
#include <vcl/pdfread.hxx>
35
#include <rtl/bootstrap.hxx>
36
37
#ifdef DBG_UTIL
38
#include <vcl/filter/PngImageWriter.hxx>
39
#endif
40
41
// GDI-Array
42
43
324k
#define EMR_HEADER                      1
44
663
#define EMR_POLYBEZIER                  2
45
2.22k
#define EMR_POLYGON                     3
46
922
#define EMR_POLYLINE                    4
47
897
#define EMR_POLYBEZIERTO                5
48
2.10k
#define EMR_POLYLINETO                  6
49
1.91k
#define EMR_POLYPOLYLINE                7
50
3.21k
#define EMR_POLYPOLYGON                 8
51
1.68k
#define EMR_SETWINDOWEXTEX              9
52
3.75k
#define EMR_SETWINDOWORGEX              10
53
1.39k
#define EMR_SETVIEWPORTEXTEX            11
54
1.13k
#define EMR_SETVIEWPORTORGEX            12
55
2.13k
#define EMR_SETBRUSHORGEX               13
56
1.04k
#define EMR_EOF                         14
57
160
#define EMR_SETPIXELV                   15
58
2.02k
#define EMR_SETMAPPERFLAGS              16
59
2.30k
#define EMR_SETMAPMODE                  17
60
738
#define EMR_SETBKMODE                   18
61
100
#define EMR_SETPOLYFILLMODE             19
62
3.32k
#define EMR_SETROP2                     20
63
567
#define EMR_SETSTRETCHBLTMODE           21
64
1.75k
#define EMR_SETTEXTALIGN                22
65
1.25k
#define EMR_SETCOLORADJUSTMENT          23
66
2.27k
#define EMR_SETTEXTCOLOR                24
67
2.17k
#define EMR_SETBKCOLOR                  25
68
311
#define EMR_OFFSETCLIPRGN               26
69
9.88k
#define EMR_MOVETOEX                    27
70
2.13k
#define EMR_SETMETARGN                  28
71
2.21k
#define EMR_EXCLUDECLIPRECT             29
72
1.45k
#define EMR_INTERSECTCLIPRECT           30
73
2.00k
#define EMR_SCALEVIEWPORTEXTEX          31
74
1.58k
#define EMR_SCALEWINDOWEXTEX            32
75
14.9k
#define EMR_SAVEDC                      33
76
2.12k
#define EMR_RESTOREDC                   34
77
533
#define EMR_SETWORLDTRANSFORM           35
78
3.29k
#define EMR_MODIFYWORLDTRANSFORM        36
79
14.4k
#define EMR_SELECTOBJECT                37
80
1.89k
#define EMR_CREATEPEN                   38
81
3.82k
#define EMR_CREATEBRUSHINDIRECT         39
82
5.75k
#define EMR_DELETEOBJECT                40
83
1.67k
#define EMR_ANGLEARC                    41
84
2.30k
#define EMR_ELLIPSE                     42
85
564
#define EMR_RECTANGLE                   43
86
2.05k
#define EMR_ROUNDRECT                   44
87
1.35k
#define EMR_ARC                         45
88
7.58k
#define EMR_CHORD                       46
89
1.67k
#define EMR_PIE                         47
90
2.51k
#define EMR_SELECTPALETTE               48
91
2.67k
#define EMR_CREATEPALETTE               49
92
947
#define EMR_SETPALETTEENTRIES           50
93
1.16k
#define EMR_RESIZEPALETTE               51
94
2.35k
#define EMR_REALIZEPALETTE              52
95
1.25k
#define EMR_EXTFLOODFILL                53
96
3.05k
#define EMR_LINETO                      54
97
5.28k
#define EMR_ARCTO                       55
98
8.19k
#define EMR_POLYDRAW                    56
99
396
#define EMR_SETARCDIRECTION             57
100
2.15k
#define EMR_SETMITERLIMIT               58
101
3.88k
#define EMR_BEGINPATH                   59
102
1.90k
#define EMR_ENDPATH                     60
103
577
#define EMR_CLOSEFIGURE                 61
104
1.28k
#define EMR_FILLPATH                    62
105
1.53k
#define EMR_STROKEANDFILLPATH           63
106
871
#define EMR_STROKEPATH                  64
107
531
#define EMR_FLATTENPATH                 65
108
534
#define EMR_WIDENPATH                   66
109
101
#define EMR_SELECTCLIPPATH              67
110
785
#define EMR_ABORTPATH                   68
111
112
335k
#define EMR_COMMENT                     70          // Contains arbitrary private data.
113
// Comment Identifiers:
114
43.7k
#define EMR_COMMENT_EMFPLUS             0x2B464D45  // Contains embedded EMF+ records.
115
2.98k
#define EMR_COMMENT_EMFSPOOL            0x00000000  // Contains embedded EMFSPOOL records.
116
41.3k
#define EMR_COMMENT_PUBLIC              0x43494447  // Specify extensions to EMF processing.
117
118
1.00k
#define EMR_FILLRGN                     71
119
336
#define EMR_FRAMERGN                    72
120
414
#define EMR_INVERTRGN                   73
121
671
#define EMR_PAINTRGN                    74
122
1.38k
#define EMR_EXTSELECTCLIPRGN            75
123
15.0k
#define EMR_BITBLT                      76
124
91.4k
#define EMR_STRETCHBLT                  77
125
220
#define EMR_MASKBLT                     78
126
328
#define EMR_PLGBLT                      79
127
334
#define EMR_SETDIBITSTODEVICE           80
128
45.7k
#define EMR_STRETCHDIBITS               81
129
3.99k
#define EMR_EXTCREATEFONTINDIRECTW      82
130
10.7k
#define EMR_EXTTEXTOUTA                 83
131
20.1k
#define EMR_EXTTEXTOUTW                 84
132
1.18k
#define EMR_POLYBEZIER16                85
133
18.5k
#define EMR_POLYGON16                   86
134
200
#define EMR_POLYLINE16                  87
135
1.84k
#define EMR_POLYBEZIERTO16              88
136
1.10k
#define EMR_POLYLINETO16                89
137
661
#define EMR_POLYPOLYLINE16              90
138
2.04k
#define EMR_POLYPOLYGON16               91
139
1.74k
#define EMR_POLYDRAW16                  92
140
2.12k
#define EMR_CREATEMONOBRUSH             93
141
11.8k
#define EMR_CREATEDIBPATTERNBRUSHPT     94
142
2.21k
#define EMR_EXTCREATEPEN                95
143
28.7k
#define EMR_POLYTEXTOUTA                96
144
24.4k
#define EMR_POLYTEXTOUTW                97
145
146
// WINDOWS VERSION >= 0x400
147
2.05k
#define EMR_SETICMMODE                  98
148
151
#define EMR_CREATECOLORSPACE            99
149
1.74k
#define EMR_SETCOLORSPACE              100
150
1.75k
#define EMR_DELETECOLORSPACE           101
151
1.76k
#define EMR_GLSRECORD                  102
152
1.77k
#define EMR_GLSBOUNDEDRECORD           103
153
1.79k
#define EMR_PIXELFORMAT                104
154
155
// WINDOWS VERSION >= 0x500
156
1.89k
#define EMR_DRAWESCAPE                 105
157
1.89k
#define EMR_EXTESCAPE                  106
158
1.90k
#define EMR_STARTDOC                   107
159
1.90k
#define EMR_SMALLTEXTOUT               108
160
1.93k
#define EMR_FORCEUFIMAPPING            109
161
1.93k
#define EMR_NAMEDESCAPE                110
162
1.93k
#define EMR_COLORCORRECTPALETTE        111
163
1.94k
#define EMR_SETICMPROFILEA             112
164
2.00k
#define EMR_SETICMPROFILEW             113
165
12.9k
#define EMR_ALPHABLEND                 114
166
2.68k
#define EMR_ALPHADIBBLEND              115
167
2.00k
#define EMR_TRANSPARENTBLT             116
168
2.00k
#define EMR_TRANSPARENTDIB             117
169
2.01k
#define EMR_GRADIENTFILL               118
170
2.01k
#define EMR_SETLINKEDUFIS              119
171
2.68k
#define EMR_SETTEXTJUSTIFICATION       120
172
173
17.9k
#define PDF_SIGNATURE 0x50444620 // "PDF "
174
175
/* [MS-EMF] - v20210625 - page 28 */
176
constexpr sal_Int32 ARCDIRECTION_CLOCKWISE = 0x00000002;
177
178
namespace
179
{
180
181
/* [MS-EMF] - v20210625 - page 41 */
182
/* 2.1.26 Point Enumeration */
183
enum EMFPointTypes
184
{
185
    PT_CLOSEFIGURE = 0x01,
186
    PT_LINETO = 0x02,
187
    PT_BEZIERTO = 0x04,
188
    PT_MOVETO = 0x06
189
};
190
191
const char *
192
record_type_name(sal_uInt32 nRecType)
193
0
{
194
0
#ifndef SAL_LOG_INFO
195
0
    (void) nRecType;
196
0
    return "";
197
#else
198
    switch( nRecType )
199
    {
200
    case EMR_HEADER: return "HEADER";
201
    case EMR_POLYBEZIER: return "POLYBEZIER";
202
    case EMR_POLYGON: return "POLYGON";
203
    case EMR_POLYLINE: return "POLYLINE";
204
    case EMR_POLYBEZIERTO: return "POLYBEZIERTO";
205
    case EMR_POLYLINETO: return "POLYLINETO";
206
    case EMR_POLYPOLYLINE: return "POLYPOLYLINE";
207
    case EMR_POLYPOLYGON: return "POLYPOLYGON";
208
    case EMR_SETWINDOWEXTEX: return "SETWINDOWEXTEX";
209
    case EMR_SETWINDOWORGEX: return "SETWINDOWORGEX";
210
    case EMR_SETVIEWPORTEXTEX: return "SETVIEWPORTEXTEX";
211
    case EMR_SETVIEWPORTORGEX: return "SETVIEWPORTORGEX";
212
    case EMR_SETBRUSHORGEX: return "SETBRUSHORGEX";
213
    case EMR_EOF: return "EOF";
214
    case EMR_SETPIXELV: return "SETPIXELV";
215
    case EMR_SETMAPPERFLAGS: return "SETMAPPERFLAGS";
216
    case EMR_SETMAPMODE: return "SETMAPMODE";
217
    case EMR_SETBKMODE: return "SETBKMODE";
218
    case EMR_SETPOLYFILLMODE: return "SETPOLYFILLMODE";
219
    case EMR_SETROP2: return "SETROP2";
220
    case EMR_SETSTRETCHBLTMODE: return "SETSTRETCHBLTMODE";
221
    case EMR_SETTEXTALIGN: return "SETTEXTALIGN";
222
    case EMR_SETCOLORADJUSTMENT: return "SETCOLORADJUSTMENT";
223
    case EMR_SETTEXTCOLOR: return "SETTEXTCOLOR";
224
    case EMR_SETBKCOLOR: return "SETBKCOLOR";
225
    case EMR_OFFSETCLIPRGN: return "OFFSETCLIPRGN";
226
    case EMR_MOVETOEX: return "MOVETOEX";
227
    case EMR_SETMETARGN: return "SETMETARGN";
228
    case EMR_EXCLUDECLIPRECT: return "EXCLUDECLIPRECT";
229
    case EMR_INTERSECTCLIPRECT: return "INTERSECTCLIPRECT";
230
    case EMR_SCALEVIEWPORTEXTEX: return "SCALEVIEWPORTEXTEX";
231
    case EMR_SCALEWINDOWEXTEX: return "SCALEWINDOWEXTEX";
232
    case EMR_SAVEDC: return "SAVEDC";
233
    case EMR_RESTOREDC: return "RESTOREDC";
234
    case EMR_SETWORLDTRANSFORM: return "SETWORLDTRANSFORM";
235
    case EMR_MODIFYWORLDTRANSFORM: return "MODIFYWORLDTRANSFORM";
236
    case EMR_SELECTOBJECT: return "SELECTOBJECT";
237
    case EMR_CREATEPEN: return "CREATEPEN";
238
    case EMR_CREATEBRUSHINDIRECT: return "CREATEBRUSHINDIRECT";
239
    case EMR_DELETEOBJECT: return "DELETEOBJECT";
240
    case EMR_ANGLEARC: return "ANGLEARC";
241
    case EMR_ELLIPSE: return "ELLIPSE";
242
    case EMR_RECTANGLE: return "RECTANGLE";
243
    case EMR_ROUNDRECT: return "ROUNDRECT";
244
    case EMR_ARC: return "ARC";
245
    case EMR_CHORD: return "CHORD";
246
    case EMR_PIE: return "PIE";
247
    case EMR_SELECTPALETTE: return "SELECTPALETTE";
248
    case EMR_CREATEPALETTE: return "CREATEPALETTE";
249
    case EMR_SETPALETTEENTRIES: return "SETPALETTEENTRIES";
250
    case EMR_RESIZEPALETTE: return "RESIZEPALETTE";
251
    case EMR_REALIZEPALETTE: return "REALIZEPALETTE";
252
    case EMR_EXTFLOODFILL: return "EXTFLOODFILL";
253
    case EMR_LINETO: return "LINETO";
254
    case EMR_ARCTO: return "ARCTO";
255
    case EMR_POLYDRAW: return "POLYDRAW";
256
    case EMR_SETARCDIRECTION: return "SETARCDIRECTION";
257
    case EMR_SETMITERLIMIT: return "SETMITERLIMIT";
258
    case EMR_BEGINPATH: return "BEGINPATH";
259
    case EMR_ENDPATH: return "ENDPATH";
260
    case EMR_CLOSEFIGURE: return "CLOSEFIGURE";
261
    case EMR_FILLPATH: return "FILLPATH";
262
    case EMR_STROKEANDFILLPATH: return "STROKEANDFILLPATH";
263
    case EMR_STROKEPATH: return "STROKEPATH";
264
    case EMR_FLATTENPATH: return "FLATTENPATH";
265
    case EMR_WIDENPATH: return "WIDENPATH";
266
    case EMR_SELECTCLIPPATH: return "SELECTCLIPPATH";
267
    case EMR_ABORTPATH: return "ABORTPATH";
268
    case EMR_COMMENT: return "COMMENT";
269
    case EMR_FILLRGN: return "FILLRGN";
270
    case EMR_FRAMERGN: return "FRAMERGN";
271
    case EMR_INVERTRGN: return "INVERTRGN";
272
    case EMR_PAINTRGN: return "PAINTRGN";
273
    case EMR_EXTSELECTCLIPRGN: return "EXTSELECTCLIPRGN";
274
    case EMR_BITBLT: return "BITBLT";
275
    case EMR_STRETCHBLT: return "STRETCHBLT";
276
    case EMR_MASKBLT: return "MASKBLT";
277
    case EMR_PLGBLT: return "PLGBLT";
278
    case EMR_SETDIBITSTODEVICE: return "SETDIBITSTODEVICE";
279
    case EMR_STRETCHDIBITS: return "STRETCHDIBITS";
280
    case EMR_EXTCREATEFONTINDIRECTW: return "EXTCREATEFONTINDIRECTW";
281
    case EMR_EXTTEXTOUTA: return "EXTTEXTOUTA";
282
    case EMR_EXTTEXTOUTW: return "EXTTEXTOUTW";
283
    case EMR_POLYBEZIER16: return "POLYBEZIER16";
284
    case EMR_POLYGON16: return "POLYGON16";
285
    case EMR_POLYLINE16: return "POLYLINE16";
286
    case EMR_POLYBEZIERTO16: return "POLYBEZIERTO16";
287
    case EMR_POLYLINETO16: return "POLYLINETO16";
288
    case EMR_POLYPOLYLINE16: return "POLYPOLYLINE16";
289
    case EMR_POLYPOLYGON16: return "POLYPOLYGON16";
290
    case EMR_POLYDRAW16: return "POLYDRAW16";
291
    case EMR_CREATEMONOBRUSH: return "CREATEMONOBRUSH";
292
    case EMR_CREATEDIBPATTERNBRUSHPT: return "CREATEDIBPATTERNBRUSHPT";
293
    case EMR_EXTCREATEPEN: return "EXTCREATEPEN";
294
    case EMR_POLYTEXTOUTA: return "POLYTEXTOUTA";
295
    case EMR_POLYTEXTOUTW: return "POLYTEXTOUTW";
296
    case EMR_SETICMMODE: return "SETICMMODE";
297
    case EMR_CREATECOLORSPACE: return "CREATECOLORSPACE";
298
    case EMR_SETCOLORSPACE: return "SETCOLORSPACE";
299
    case EMR_DELETECOLORSPACE: return "DELETECOLORSPACE";
300
    case EMR_GLSRECORD: return "GLSRECORD";
301
    case EMR_GLSBOUNDEDRECORD: return "GLSBOUNDEDRECORD";
302
    case EMR_PIXELFORMAT: return "PIXELFORMAT";
303
    case EMR_DRAWESCAPE: return "DRAWESCAPE";
304
    case EMR_EXTESCAPE: return "EXTESCAPE";
305
    case EMR_STARTDOC: return "STARTDOC";
306
    case EMR_SMALLTEXTOUT: return "SMALLTEXTOUT";
307
    case EMR_FORCEUFIMAPPING: return "FORCEUFIMAPPING";
308
    case EMR_NAMEDESCAPE: return "NAMEDESCAPE";
309
    case EMR_COLORCORRECTPALETTE: return "COLORCORRECTPALETTE";
310
    case EMR_SETICMPROFILEA: return "SETICMPROFILEA";
311
    case EMR_SETICMPROFILEW: return "SETICMPROFILEW";
312
    case EMR_ALPHABLEND: return "ALPHABLEND";
313
    case EMR_ALPHADIBBLEND: return "ALPHADIBBLEND";
314
    case EMR_TRANSPARENTBLT: return "TRANSPARENTBLT";
315
    case EMR_TRANSPARENTDIB: return "TRANSPARENTDIB";
316
    case EMR_GRADIENTFILL: return "GRADIENTFILL";
317
    case EMR_SETLINKEDUFIS: return "SETLINKEDUFIS";
318
    case EMR_SETTEXTJUSTIFICATION: return "SETTEXTJUSTIFICATION";
319
    default:
320
        // Yes, return a pointer to a static buffer. This is a very
321
        // local debugging output function, so no big deal.
322
        static char buffer[11];
323
        o3tl::sprintf(buffer, "0x%08" SAL_PRIxUINT32, nRecType);
324
        return buffer;
325
    }
326
#endif
327
0
}
328
329
struct BLENDFUNCTION
330
{
331
    unsigned char aBlendOperation;
332
    unsigned char aBlendFlags;
333
    unsigned char aSrcConstantAlpha;
334
    unsigned char aAlphaFormat;
335
336
    friend SvStream& operator>>(SvStream& rInStream, BLENDFUNCTION& rBlendFun);
337
};
338
339
SvStream& operator>>(SvStream& rInStream, BLENDFUNCTION& rBlendFun)
340
12.9k
{
341
12.9k
    rInStream.ReadUChar(rBlendFun.aBlendOperation);
342
12.9k
    rInStream.ReadUChar(rBlendFun.aBlendFlags);
343
12.9k
    rInStream.ReadUChar(rBlendFun.aSrcConstantAlpha);
344
12.9k
    rInStream.ReadUChar(rBlendFun.aAlphaFormat);
345
12.9k
    return rInStream;
346
12.9k
}
347
348
bool ImplReadRegion( basegfx::B2DPolyPolygon& rPolyPoly, SvStream& rStream, sal_uInt32 nLen, Point aWinOrg )
349
2.19k
{
350
2.19k
    if (nLen < 32) // 32 bytes - Size of RegionDataHeader
351
181
        return false;
352
353
2.01k
    sal_uInt32 nHdSize, nType, nCountRects, nRgnSize;
354
2.01k
    rStream.ReadUInt32(nHdSize);
355
2.01k
    rStream.ReadUInt32(nType);
356
2.01k
    rStream.ReadUInt32(nCountRects);
357
2.01k
    rStream.ReadUInt32(nRgnSize);
358
359
2.01k
    sal_Int32 nLeft, nTop, nRight, nBottom;
360
    //bounds of the region
361
2.01k
    rStream.ReadInt32(nLeft);
362
2.01k
    rStream.ReadInt32(nTop);
363
2.01k
    rStream.ReadInt32(nRight);
364
2.01k
    rStream.ReadInt32(nBottom);
365
366
2.01k
    if (!rStream.good() || nCountRects == 0 || nType != emfio::RDH_RECTANGLES)
367
447
        return false;
368
369
1.56k
    SAL_INFO("emfio", "\t\tBounds Left: " << nLeft << ", top: " << nTop << ", right: " << nRight << ", bottom: " << nBottom);
370
371
1.56k
    nLen -= 32;
372
373
1.56k
    sal_uInt32 nSize;
374
1.56k
    if (o3tl::checked_multiply<sal_uInt32>(nCountRects, 16, nSize))
375
153
        return false;
376
1.41k
    if (nLen < nSize)
377
384
        return false;
378
379
4.28k
    for (sal_uInt32 i = 0; i < nCountRects; ++i)
380
3.25k
    {
381
3.25k
        rStream.ReadInt32(nLeft);
382
3.25k
        rStream.ReadInt32(nTop);
383
3.25k
        rStream.ReadInt32(nRight);
384
3.25k
        rStream.ReadInt32(nBottom);
385
3.25k
        nLeft += aWinOrg.X();
386
3.25k
        nRight += aWinOrg.X();
387
3.25k
        nTop += aWinOrg.Y();
388
3.25k
        nBottom += aWinOrg.Y();
389
3.25k
        rPolyPoly.append( basegfx::utils::createPolygonFromRect( ::basegfx::B2DRectangle( nLeft, nTop, nRight, nBottom ) ) );
390
3.25k
        SAL_INFO("emfio", "\t\t" << i << " Left: " << nLeft << ", top: " << nTop << ", right: " << nRight << ", bottom: " << nBottom);
391
3.25k
    }
392
1.02k
    if (!comphelper::IsFuzzing())
393
0
    {
394
0
        rPolyPoly = basegfx::utils::solveCrossovers(rPolyPoly);
395
0
        rPolyPoly = basegfx::utils::stripNeutralPolygons(rPolyPoly);
396
0
        rPolyPoly = basegfx::utils::stripDispensablePolygons(rPolyPoly);
397
0
    }
398
1.02k
    return true;
399
1.02k
}
400
401
} // anonymous namespace
402
403
namespace emfio
404
{
405
    EmfReader::EmfReader(SvStream& rStream,GDIMetaFile& rGDIMetaFile)
406
8.66k
        : MtfTools(rGDIMetaFile, rStream)
407
8.66k
        , mnRecordCount(0)
408
8.66k
        , mbRecordPath(false)
409
8.66k
        , mbEMFPlus(false)
410
8.66k
        , mbEMFPlusDualMode(false)
411
8.66k
    {
412
8.66k
    }
413
414
    EmfReader::~EmfReader()
415
8.66k
    {
416
8.66k
    }
417
418
    const sal_uInt32 EMR_COMMENT_BEGINGROUP = 0x00000002;
419
    const sal_uInt32 EMR_COMMENT_ENDGROUP = 0x00000003;
420
    const sal_uInt32 EMR_COMMENT_MULTIFORMATS = 0x40000004;
421
    const sal_uInt32 EMR_COMMENT_WINDOWS_METAFILE = 0x80000001;
422
423
    void EmfReader::ReadGDIComment(sal_uInt32 nCommentId)
424
19.1k
    {
425
19.1k
        sal_uInt32 nPublicCommentIdentifier(0);
426
19.1k
        mpInputStream->ReadUInt32(nPublicCommentIdentifier);
427
428
19.1k
        SAL_INFO("emfio", "\t\tEMR_COMMENT_PUBLIC, id: 0x" << std::hex << nCommentId << std::dec);
429
19.1k
        switch (nPublicCommentIdentifier)
430
19.1k
        {
431
242
            case EMR_COMMENT_BEGINGROUP:
432
242
            {
433
242
                SAL_INFO("emfio", "\t\t\tEMR_COMMENT_BEGINGROUP");
434
242
                sal_uInt32 left, top, right, bottom;
435
242
                mpInputStream->ReadUInt32(left).ReadUInt32(top).ReadUInt32(right).ReadUInt32(bottom);
436
437
242
                SAL_INFO("emfio", "\t\t\t\tBounding rect");
438
242
                SAL_INFO("emfio", "\t\t\t\t\tLeft: " << left);
439
242
                SAL_INFO("emfio", "\t\t\t\t\tTop: " << top);
440
242
                SAL_INFO("emfio", "\t\t\t\t\tRight: " << right);
441
242
                SAL_INFO("emfio", "\t\t\t\t\tBottom: " << bottom);
442
443
242
                sal_uInt32 nDescChars(0);
444
242
                mpInputStream->ReadUInt32(nDescChars);
445
446
242
                OUStringBuffer aDesc;
447
19.8k
                for (sal_uInt32 i=0; i < nDescChars; i++)
448
19.6k
                {
449
19.6k
                    sal_uInt16 cChar(0);
450
19.6k
                    mpInputStream->ReadUInt16(cChar);
451
19.6k
                    if (cChar == '\0')
452
62
                        break;
453
454
19.6k
                    sal_Unicode cUniChar = static_cast<sal_Unicode>(cChar);
455
19.6k
                    aDesc.append(OUStringChar(cUniChar));
456
19.6k
                }
457
458
242
                SAL_INFO("emfio", "\t\tDescription: " << aDesc.toString());
459
242
            }
460
242
            break;
461
462
242
            case EMR_COMMENT_ENDGROUP:
463
84
                SAL_INFO("emfio", "\t\t\tEMR_COMMENT_ENDGROUP");
464
84
                break;
465
466
17.9k
            case EMR_COMMENT_MULTIFORMATS:
467
17.9k
                ReadMultiformatsComment();
468
17.9k
                break;
469
470
0
            case EMR_COMMENT_WINDOWS_METAFILE:
471
0
                SAL_WARN("emfio", "\t\tEMR_COMMENT_WINDOWS_METAFILE not implemented");
472
0
                break;
473
474
856
            default:
475
856
                SAL_WARN("emfio", "\t\tEMR_COMMENT_PUBLIC not implemented, id: 0x" << std::hex << nCommentId << std::dec);
476
856
                break;
477
19.1k
        }
478
19.1k
    }
479
480
    void EmfReader::ReadMultiformatsComment()
481
17.9k
    {
482
17.9k
        tools::Rectangle aOutputRect = EmfReader::ReadRectangle();
483
484
17.9k
        sal_uInt32 nCountFormats(0);
485
17.9k
        mpInputStream->ReadUInt32(nCountFormats);
486
17.9k
        if (nCountFormats < 1)
487
77
        {
488
77
            return;
489
77
        }
490
491
        // Read the first EmrFormat.
492
17.9k
        sal_uInt32 nSignature(0);
493
17.9k
        mpInputStream->ReadUInt32(nSignature);
494
17.9k
        if (nSignature != PDF_SIGNATURE)
495
2.55k
        {
496
2.55k
            return;
497
2.55k
        }
498
499
15.3k
        sal_uInt32 nVersion(0);
500
15.3k
        mpInputStream->ReadUInt32(nVersion);
501
15.3k
        if (nVersion != 1)
502
630
        {
503
630
            return;
504
630
        }
505
506
14.7k
        sal_uInt32 nSizeData(0);
507
14.7k
        mpInputStream->ReadUInt32(nSizeData);
508
14.7k
        if (!nSizeData || nSizeData > mpInputStream->remainingSize())
509
2.57k
        {
510
2.57k
            return;
511
2.57k
        }
512
513
12.1k
        sal_uInt32 nOffData(0);
514
12.1k
        mpInputStream->ReadUInt32(nOffData);
515
12.1k
        if (!nOffData)
516
49
        {
517
49
            return;
518
49
        }
519
520
12.1k
        std::vector<char> aPdfData(nSizeData);
521
12.1k
        mpInputStream->ReadBytes(aPdfData.data(), aPdfData.size());
522
12.1k
        if (!mpInputStream->good())
523
9
        {
524
9
            return;
525
9
        }
526
527
12.0k
        SvMemoryStream aPdfStream;
528
12.0k
        aPdfStream.WriteBytes(aPdfData.data(), aPdfData.size());
529
12.0k
        aPdfStream.Seek(0);
530
12.0k
        Graphic aGraphic;
531
12.0k
        if (!vcl::ImportPDF(aPdfStream, aGraphic))
532
11.3k
        {
533
11.3k
            return;
534
11.3k
        }
535
536
        // aGraphic will be the only output of the EMF parser, so its size hint can be the same as
537
        // ours.
538
770
        aGraphic.getVectorGraphicData()->setSizeHint(maSizeHint);
539
540
770
        maBmpSaveList.emplace_back(
541
770
            aGraphic.GetBitmap(), aOutputRect, SRCCOPY, /*bForceAlpha=*/true);
542
770
        const std::shared_ptr<VectorGraphicData> pVectorGraphicData
543
770
            = aGraphic.getVectorGraphicData();
544
770
        if (!pVectorGraphicData)
545
0
        {
546
0
            return;
547
0
        }
548
549
770
        if (pVectorGraphicData->getType() != VectorGraphicDataType::Pdf)
550
0
        {
551
0
            return;
552
0
        }
553
554
770
        mbReadOtherGraphicFormat = true;
555
770
    }
556
557
    void EmfReader::ReadEMFPlusComment(sal_uInt32 length, bool& bHaveDC)
558
1.21k
    {
559
1.21k
        if (!mbEMFPlus)
560
203
        {
561
203
            PassEMFPlusHeaderInfo();
562
563
    #if OSL_DEBUG_LEVEL > 1
564
            // debug code - write the stream to debug file /tmp/emf-stream.emf
565
            sal_uInt64 const pos = mpInputStream->Tell();
566
            mpInputStream->Seek(0);
567
            SvFileStream file( OUString( "/tmp/emf-stream.emf" ), StreamMode::WRITE | StreamMode::TRUNC );
568
569
            mpInputStream->WriteStream(file);
570
            file.Flush();
571
            file.Close();
572
573
            mpInputStream->Seek( pos );
574
    #endif
575
576
203
        }
577
578
1.21k
        mbEMFPlus = true;
579
1.21k
        sal_uInt64 const pos = mpInputStream->Tell();
580
1.21k
        auto buffer = std::make_unique<char[]>( length );
581
1.21k
        PassEMFPlus( buffer.get(), mpInputStream->ReadBytes(buffer.get(), length) );
582
1.21k
        buffer.reset();
583
1.21k
        mpInputStream->Seek( pos );
584
585
1.21k
        bHaveDC = false;
586
587
        // skip in SeekRel if impossibly unavailable
588
1.21k
        sal_uInt32 nRemainder = length;
589
590
1.21k
        const size_t nRequiredHeaderSize = 12;
591
5.05k
        while (nRemainder >= nRequiredHeaderSize)
592
3.84k
        {
593
3.84k
            sal_uInt16 type(0), flags(0);
594
3.84k
            sal_uInt32 size(0), dataSize(0);
595
596
3.84k
            mpInputStream->ReadUInt16( type ).ReadUInt16( flags ).ReadUInt32( size ).ReadUInt32( dataSize );
597
3.84k
            nRemainder -= nRequiredHeaderSize;
598
599
3.84k
            SAL_INFO("emfio", "\t\tEMF+ record type: 0x" << std::hex << type << std::dec);
600
601
            // Get Device Context
602
            // TODO We should use  EmfPlusRecordType::GetDC instead
603
3.84k
            if( type == 0x4004 )
604
724
            {
605
724
                bHaveDC = true;
606
724
                SAL_INFO("emfio", "\t\tEMF+ lock DC (device context)");
607
724
            }
608
609
            // look for the "dual mode" in header
610
            // it indicates that either EMF or EMF+ records should be processed
611
            // 0x4001    = EMF+ header
612
            // flags & 1 = dual mode active
613
3.84k
            if ( type == 0x4001 && flags & 1 )
614
213
            {
615
213
                mbEMFPlusDualMode = true;
616
213
                SAL_INFO ("emfio", "\t\tEMF+ dual mode detected");
617
213
            }
618
619
            // Get the length of the remaining data of this record based
620
            // on the alleged size
621
3.84k
            sal_uInt32 nRemainingRecordData = size >= nRequiredHeaderSize ?
622
2.69k
                size-nRequiredHeaderSize : 0;
623
            // clip to available size
624
3.84k
            nRemainingRecordData = std::min(nRemainingRecordData, nRemainder);
625
3.84k
            mpInputStream->SeekRel(nRemainingRecordData);
626
3.84k
            nRemainder -= nRemainingRecordData;
627
3.84k
        }
628
1.21k
        mpInputStream->SeekRel(nRemainder);
629
1.21k
    }
630
631
    // these are referenced from inside the templates
632
    static SvStream& operator >> (SvStream& rStream, sal_Int16 &n)
633
4.32M
    {
634
4.32M
        return rStream.ReadInt16(n);
635
4.32M
    }
636
637
    static SvStream& operator >> (SvStream& rStream, sal_Int32 &n)
638
6.27M
    {
639
6.27M
        return rStream.ReadInt32(n);
640
6.27M
    }
641
642
    /**
643
     * Reads polygons from the stream.
644
     * The \<class T> parameter is for the type of the points (sal_uInt32 or sal_uInt16).
645
     * skipFirst: if the first point read is the 0th point or the 1st point in the array.
646
     * */
647
    template <class T>
648
    tools::Polygon EmfReader::ReadPolygonWithSkip(const bool skipFirst, sal_uInt32 nNextPos)
649
29.7k
    {
650
29.7k
        sal_uInt32 nPoints(0), nStartIndex(0);
651
29.7k
        mpInputStream->SeekRel( 16 );
652
29.7k
        mpInputStream->ReadUInt32( nPoints );
653
29.7k
        if (skipFirst)
654
5.95k
        {
655
5.95k
            nPoints ++;
656
5.95k
            nStartIndex ++;
657
5.95k
        }
658
659
29.7k
        return ReadPolygon<T>(nStartIndex, nPoints, nNextPos);
660
29.7k
    }
tools::Polygon emfio::EmfReader::ReadPolygonWithSkip<int>(bool, unsigned int)
Line
Count
Source
649
6.80k
    {
650
6.80k
        sal_uInt32 nPoints(0), nStartIndex(0);
651
6.80k
        mpInputStream->SeekRel( 16 );
652
6.80k
        mpInputStream->ReadUInt32( nPoints );
653
6.80k
        if (skipFirst)
654
3.00k
        {
655
3.00k
            nPoints ++;
656
3.00k
            nStartIndex ++;
657
3.00k
        }
658
659
6.80k
        return ReadPolygon<T>(nStartIndex, nPoints, nNextPos);
660
6.80k
    }
tools::Polygon emfio::EmfReader::ReadPolygonWithSkip<short>(bool, unsigned int)
Line
Count
Source
649
22.9k
    {
650
22.9k
        sal_uInt32 nPoints(0), nStartIndex(0);
651
22.9k
        mpInputStream->SeekRel( 16 );
652
22.9k
        mpInputStream->ReadUInt32( nPoints );
653
22.9k
        if (skipFirst)
654
2.95k
        {
655
2.95k
            nPoints ++;
656
2.95k
            nStartIndex ++;
657
2.95k
        }
658
659
22.9k
        return ReadPolygon<T>(nStartIndex, nPoints, nNextPos);
660
22.9k
    }
661
662
    /**
663
     * Reads polygons from the stream.
664
     * The \<class T> parameter is for the type of the points
665
     * nStartIndex: which is the starting index in the polygon of the first point read
666
     * nPoints: number of points
667
     * mpInputStream: the stream containing the polygons
668
     * */
669
    template <class T>
670
    tools::Polygon EmfReader::ReadPolygon(sal_uInt32 nStartIndex, sal_uInt32 nPoints, sal_uInt32 nNextPos)
671
32.4k
    {
672
32.4k
        SAL_INFO ("emfio", "\t\tPolygon:");
673
674
32.4k
        bool bRecordOk = nPoints <= SAL_MAX_UINT16;
675
32.4k
        SAL_WARN_IF(!bRecordOk, "emfio", "polygon record has more polygons than we can handle");
676
32.4k
        if (!bRecordOk || !nPoints)
677
6.31k
            return tools::Polygon();
678
679
26.1k
        auto nRemainingSize = std::min(nNextPos - mpInputStream->Tell(), mpInputStream->remainingSize());
680
26.1k
        auto nMaxPossiblePoints = nRemainingSize / (sizeof(T) * 2);
681
26.1k
        auto nPointCount = nPoints - nStartIndex;
682
26.1k
        if (nPointCount > nMaxPossiblePoints)
683
4.56k
        {
684
4.56k
            SAL_WARN("emfio", "polygon claims more points than record can provide, truncating");
685
4.56k
            nPoints = nMaxPossiblePoints + nStartIndex;
686
4.56k
        }
687
688
26.1k
        tools::Polygon aPolygon(nPoints);
689
1.77M
        for (sal_uInt32 i = nStartIndex ; i < nPoints && mpInputStream->good(); i++ )
690
1.74M
        {
691
1.74M
            T nX, nY;
692
1.74M
            *mpInputStream >> nX >> nY;
693
694
1.74M
            SAL_INFO("emfio", "\t\t\tPoint " << i << " of " << nPoints - 1 << ": " << nX << ", " << nY);
695
696
1.74M
            if (!mpInputStream->good())
697
0
            {
698
0
                SAL_WARN("emfio", "short read on polygon, truncating");
699
0
                aPolygon.SetSize(i);
700
0
                break;
701
0
            }
702
1.74M
            aPolygon[ i ] = Point( nX, nY );
703
1.74M
        }
704
705
26.1k
        return aPolygon;
706
26.1k
    }
tools::Polygon emfio::EmfReader::ReadPolygon<int>(unsigned int, unsigned int, unsigned int)
Line
Count
Source
671
7.90k
    {
672
7.90k
        SAL_INFO ("emfio", "\t\tPolygon:");
673
674
7.90k
        bool bRecordOk = nPoints <= SAL_MAX_UINT16;
675
7.90k
        SAL_WARN_IF(!bRecordOk, "emfio", "polygon record has more polygons than we can handle");
676
7.90k
        if (!bRecordOk || !nPoints)
677
2.24k
            return tools::Polygon();
678
679
5.66k
        auto nRemainingSize = std::min(nNextPos - mpInputStream->Tell(), mpInputStream->remainingSize());
680
5.66k
        auto nMaxPossiblePoints = nRemainingSize / (sizeof(T) * 2);
681
5.66k
        auto nPointCount = nPoints - nStartIndex;
682
5.66k
        if (nPointCount > nMaxPossiblePoints)
683
1.16k
        {
684
1.16k
            SAL_WARN("emfio", "polygon claims more points than record can provide, truncating");
685
1.16k
            nPoints = nMaxPossiblePoints + nStartIndex;
686
1.16k
        }
687
688
5.66k
        tools::Polygon aPolygon(nPoints);
689
189k
        for (sal_uInt32 i = nStartIndex ; i < nPoints && mpInputStream->good(); i++ )
690
183k
        {
691
183k
            T nX, nY;
692
183k
            *mpInputStream >> nX >> nY;
693
694
183k
            SAL_INFO("emfio", "\t\t\tPoint " << i << " of " << nPoints - 1 << ": " << nX << ", " << nY);
695
696
183k
            if (!mpInputStream->good())
697
0
            {
698
0
                SAL_WARN("emfio", "short read on polygon, truncating");
699
0
                aPolygon.SetSize(i);
700
0
                break;
701
0
            }
702
183k
            aPolygon[ i ] = Point( nX, nY );
703
183k
        }
704
705
5.66k
        return aPolygon;
706
5.66k
    }
tools::Polygon emfio::EmfReader::ReadPolygon<short>(unsigned int, unsigned int, unsigned int)
Line
Count
Source
671
24.5k
    {
672
24.5k
        SAL_INFO ("emfio", "\t\tPolygon:");
673
674
24.5k
        bool bRecordOk = nPoints <= SAL_MAX_UINT16;
675
24.5k
        SAL_WARN_IF(!bRecordOk, "emfio", "polygon record has more polygons than we can handle");
676
24.5k
        if (!bRecordOk || !nPoints)
677
4.06k
            return tools::Polygon();
678
679
20.4k
        auto nRemainingSize = std::min(nNextPos - mpInputStream->Tell(), mpInputStream->remainingSize());
680
20.4k
        auto nMaxPossiblePoints = nRemainingSize / (sizeof(T) * 2);
681
20.4k
        auto nPointCount = nPoints - nStartIndex;
682
20.4k
        if (nPointCount > nMaxPossiblePoints)
683
3.40k
        {
684
3.40k
            SAL_WARN("emfio", "polygon claims more points than record can provide, truncating");
685
3.40k
            nPoints = nMaxPossiblePoints + nStartIndex;
686
3.40k
        }
687
688
20.4k
        tools::Polygon aPolygon(nPoints);
689
1.58M
        for (sal_uInt32 i = nStartIndex ; i < nPoints && mpInputStream->good(); i++ )
690
1.56M
        {
691
1.56M
            T nX, nY;
692
1.56M
            *mpInputStream >> nX >> nY;
693
694
1.56M
            SAL_INFO("emfio", "\t\t\tPoint " << i << " of " << nPoints - 1 << ": " << nX << ", " << nY);
695
696
1.56M
            if (!mpInputStream->good())
697
0
            {
698
0
                SAL_WARN("emfio", "short read on polygon, truncating");
699
0
                aPolygon.SetSize(i);
700
0
                break;
701
0
            }
702
1.56M
            aPolygon[ i ] = Point( nX, nY );
703
1.56M
        }
704
705
20.4k
        return aPolygon;
706
20.4k
    }
707
708
    /**
709
     * Reads a polyline from the WMF file and draws it
710
     * The \<class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32)
711
     * */
712
    template <class T>
713
    void EmfReader::ReadAndDrawPolyLine(sal_uInt32 nNextPos)
714
2.57k
    {
715
2.57k
        SAL_INFO("emfio", "\t\tPolyline: ");
716
717
2.57k
        mpInputStream->SeekRel( 0x10 ); // TODO Skipping Bounds. A 128-bit WMF RectL object (specifies the bounding rectangle in device units.)
718
719
2.57k
        sal_uInt32 nNumberOfPolylines = 0;
720
2.57k
        mpInputStream->ReadUInt32( nNumberOfPolylines );
721
2.57k
        SAL_INFO("emfio", "\t\t\tPolylines: " << nNumberOfPolylines);
722
723
2.57k
        sal_uInt32 nCount = 0;
724
2.57k
        mpInputStream->ReadUInt32( nCount ); // total number of points in all polylines
725
2.57k
        SAL_INFO("emfio", "\t\t\tPoints: " << nCount);
726
727
2.57k
        const auto nEndPos = std::min(nNextPos, mnEndPos);
728
2.57k
        if (mpInputStream->Tell() >= nEndPos)
729
1.46k
            return;
730
731
        // taking the amount of points of each polygon, retrieving the total number of points
732
1.10k
        if ( !(mpInputStream->good() &&
733
1.10k
             ( nNumberOfPolylines < SAL_MAX_UINT32 / sizeof( sal_uInt16 ) ) &&
734
805
             ( nNumberOfPolylines * sizeof( sal_uInt16 ) ) <= ( nEndPos - mpInputStream->Tell() ))
735
1.10k
           )
736
867
            return;
737
738
241
        std::unique_ptr< sal_uInt32[] > pnPolylinePointCount( new sal_uInt32[ nNumberOfPolylines ] );
739
3.07k
        for ( sal_uInt32 i = 0; i < nNumberOfPolylines && mpInputStream->good(); i++ )
740
2.83k
        {
741
2.83k
            sal_uInt32 nPoints;
742
2.83k
            mpInputStream->ReadUInt32( nPoints );
743
2.83k
            SAL_INFO("emfio", "\t\t\tPoint " << i << " of " << nNumberOfPolylines << ": " << nPoints);
744
2.83k
            pnPolylinePointCount[ i ] = nPoints;
745
2.83k
        }
746
747
        // Get polyline points:
748
2.94k
        for ( sal_uInt32 i = 0; ( i < nNumberOfPolylines ) && mpInputStream->good(); i++ )
749
2.69k
        {
750
2.69k
            tools::Polygon aPolygon = ReadPolygon<T>(0, pnPolylinePointCount[i], nNextPos);
751
2.69k
            DrawPolyLine(std::move(aPolygon), false, mbRecordPath);
752
2.69k
        }
753
241
    }
void emfio::EmfReader::ReadAndDrawPolyLine<int>(unsigned int)
Line
Count
Source
714
1.91k
    {
715
1.91k
        SAL_INFO("emfio", "\t\tPolyline: ");
716
717
1.91k
        mpInputStream->SeekRel( 0x10 ); // TODO Skipping Bounds. A 128-bit WMF RectL object (specifies the bounding rectangle in device units.)
718
719
1.91k
        sal_uInt32 nNumberOfPolylines = 0;
720
1.91k
        mpInputStream->ReadUInt32( nNumberOfPolylines );
721
1.91k
        SAL_INFO("emfio", "\t\t\tPolylines: " << nNumberOfPolylines);
722
723
1.91k
        sal_uInt32 nCount = 0;
724
1.91k
        mpInputStream->ReadUInt32( nCount ); // total number of points in all polylines
725
1.91k
        SAL_INFO("emfio", "\t\t\tPoints: " << nCount);
726
727
1.91k
        const auto nEndPos = std::min(nNextPos, mnEndPos);
728
1.91k
        if (mpInputStream->Tell() >= nEndPos)
729
1.22k
            return;
730
731
        // taking the amount of points of each polygon, retrieving the total number of points
732
693
        if ( !(mpInputStream->good() &&
733
693
             ( nNumberOfPolylines < SAL_MAX_UINT32 / sizeof( sal_uInt16 ) ) &&
734
514
             ( nNumberOfPolylines * sizeof( sal_uInt16 ) ) <= ( nEndPos - mpInputStream->Tell() ))
735
693
           )
736
564
            return;
737
738
129
        std::unique_ptr< sal_uInt32[] > pnPolylinePointCount( new sal_uInt32[ nNumberOfPolylines ] );
739
1.26k
        for ( sal_uInt32 i = 0; i < nNumberOfPolylines && mpInputStream->good(); i++ )
740
1.14k
        {
741
1.14k
            sal_uInt32 nPoints;
742
1.14k
            mpInputStream->ReadUInt32( nPoints );
743
1.14k
            SAL_INFO("emfio", "\t\t\tPoint " << i << " of " << nNumberOfPolylines << ": " << nPoints);
744
1.14k
            pnPolylinePointCount[ i ] = nPoints;
745
1.14k
        }
746
747
        // Get polyline points:
748
1.22k
        for ( sal_uInt32 i = 0; ( i < nNumberOfPolylines ) && mpInputStream->good(); i++ )
749
1.10k
        {
750
1.10k
            tools::Polygon aPolygon = ReadPolygon<T>(0, pnPolylinePointCount[i], nNextPos);
751
1.10k
            DrawPolyLine(std::move(aPolygon), false, mbRecordPath);
752
1.10k
        }
753
129
    }
void emfio::EmfReader::ReadAndDrawPolyLine<short>(unsigned int)
Line
Count
Source
714
661
    {
715
661
        SAL_INFO("emfio", "\t\tPolyline: ");
716
717
661
        mpInputStream->SeekRel( 0x10 ); // TODO Skipping Bounds. A 128-bit WMF RectL object (specifies the bounding rectangle in device units.)
718
719
661
        sal_uInt32 nNumberOfPolylines = 0;
720
661
        mpInputStream->ReadUInt32( nNumberOfPolylines );
721
661
        SAL_INFO("emfio", "\t\t\tPolylines: " << nNumberOfPolylines);
722
723
661
        sal_uInt32 nCount = 0;
724
661
        mpInputStream->ReadUInt32( nCount ); // total number of points in all polylines
725
661
        SAL_INFO("emfio", "\t\t\tPoints: " << nCount);
726
727
661
        const auto nEndPos = std::min(nNextPos, mnEndPos);
728
661
        if (mpInputStream->Tell() >= nEndPos)
729
246
            return;
730
731
        // taking the amount of points of each polygon, retrieving the total number of points
732
415
        if ( !(mpInputStream->good() &&
733
415
             ( nNumberOfPolylines < SAL_MAX_UINT32 / sizeof( sal_uInt16 ) ) &&
734
291
             ( nNumberOfPolylines * sizeof( sal_uInt16 ) ) <= ( nEndPos - mpInputStream->Tell() ))
735
415
           )
736
303
            return;
737
738
112
        std::unique_ptr< sal_uInt32[] > pnPolylinePointCount( new sal_uInt32[ nNumberOfPolylines ] );
739
1.80k
        for ( sal_uInt32 i = 0; i < nNumberOfPolylines && mpInputStream->good(); i++ )
740
1.69k
        {
741
1.69k
            sal_uInt32 nPoints;
742
1.69k
            mpInputStream->ReadUInt32( nPoints );
743
1.69k
            SAL_INFO("emfio", "\t\t\tPoint " << i << " of " << nNumberOfPolylines << ": " << nPoints);
744
1.69k
            pnPolylinePointCount[ i ] = nPoints;
745
1.69k
        }
746
747
        // Get polyline points:
748
1.71k
        for ( sal_uInt32 i = 0; ( i < nNumberOfPolylines ) && mpInputStream->good(); i++ )
749
1.59k
        {
750
1.59k
            tools::Polygon aPolygon = ReadPolygon<T>(0, pnPolylinePointCount[i], nNextPos);
751
1.59k
            DrawPolyLine(std::move(aPolygon), false, mbRecordPath);
752
1.59k
        }
753
112
    }
754
755
    /**
756
     * Reads a poly polygon from the WMF file and draws it.
757
     * The \<class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32)
758
     * */
759
    template <class T>
760
    void EmfReader::ReadAndDrawPolyPolygon(sal_uInt32 nNextPos)
761
5.26k
    {
762
5.26k
        SAL_INFO("emfio", "\t\tPolygon: ");
763
5.26k
        mpInputStream->SeekRel( 0x10 ); // RectL bounds
764
765
5.26k
        sal_uInt32 nPoly(0), nGesPoints(0), nReadPoints(0);
766
        // Number of polygons
767
5.26k
        mpInputStream->ReadUInt32( nPoly ).ReadUInt32( nGesPoints );
768
5.26k
        SAL_INFO("emfio", "\t\t\tPolygons: " << nPoly);
769
5.26k
        SAL_INFO("emfio", "\t\t\tPoints: " << nGesPoints);
770
771
5.26k
        const auto nEndPos = std::min(nNextPos, mnEndPos);
772
5.26k
        if (mpInputStream->Tell() >= nEndPos)
773
1.51k
            return;
774
3.74k
        if (!mpInputStream->good())
775
0
            return;
776
        //check against numeric overflowing
777
3.74k
        if (nGesPoints >= SAL_MAX_UINT32 / sizeof(Point))
778
417
            return;
779
3.33k
        if (nPoly >= SAL_MAX_UINT32 / sizeof(sal_uInt16))
780
132
            return;
781
3.19k
        if (nPoly * sizeof(sal_uInt16) > nEndPos - mpInputStream->Tell())
782
986
            return;
783
784
        // Get number of points in each polygon
785
2.21k
        std::vector<sal_uInt16> aPoints(nPoly);
786
12.6k
        for (sal_uInt32 i = 0; i < nPoly && mpInputStream->good(); ++i)
787
10.4k
        {
788
10.4k
            sal_uInt32 nPoints(0);
789
10.4k
            mpInputStream->ReadUInt32( nPoints );
790
791
10.4k
            SAL_INFO("emfio", "\t\t\t\tPolygon " << i << " points: " << nPoints);
792
793
10.4k
            aPoints[i] = static_cast<sal_uInt16>(nPoints);
794
10.4k
        }
795
796
2.21k
        if ( mpInputStream->good() && ( nGesPoints * (sizeof(T)+sizeof(T)) ) <= ( nEndPos - mpInputStream->Tell() ) )
797
1.80k
        {
798
            // Get polygon points
799
1.80k
            tools::PolyPolygon aPolyPoly(nPoly);
800
7.54k
            for (sal_uInt32 i = 0; i < nPoly && mpInputStream->good(); ++i)
801
5.74k
            {
802
5.74k
                const sal_uInt16 nPointCount(aPoints[i]);
803
5.74k
                std::vector<Point> aPtAry(nPointCount);
804
1.29M
                for (sal_uInt16 j = 0; j < nPointCount && mpInputStream->good(); ++j)
805
1.28M
                {
806
1.28M
                    T nX(0), nY(0);
807
1.28M
                    *mpInputStream >> nX >> nY;
808
1.28M
                    aPtAry[j] = Point( nX, nY );
809
1.28M
                    ++nReadPoints;
810
1.28M
                }
811
812
5.74k
                aPolyPoly.Insert(tools::Polygon(aPtAry.size(), aPtAry.data()));
813
5.74k
            }
814
815
1.80k
            DrawPolyPolygon(aPolyPoly, mbRecordPath);
816
1.80k
        }
817
818
2.21k
        OSL_ENSURE(nReadPoints == nGesPoints, "The number Points processed from EMR_POLYPOLYGON is unequal imported number (!)");
819
2.21k
    }
void emfio::EmfReader::ReadAndDrawPolyPolygon<int>(unsigned int)
Line
Count
Source
761
3.21k
    {
762
3.21k
        SAL_INFO("emfio", "\t\tPolygon: ");
763
3.21k
        mpInputStream->SeekRel( 0x10 ); // RectL bounds
764
765
3.21k
        sal_uInt32 nPoly(0), nGesPoints(0), nReadPoints(0);
766
        // Number of polygons
767
3.21k
        mpInputStream->ReadUInt32( nPoly ).ReadUInt32( nGesPoints );
768
3.21k
        SAL_INFO("emfio", "\t\t\tPolygons: " << nPoly);
769
3.21k
        SAL_INFO("emfio", "\t\t\tPoints: " << nGesPoints);
770
771
3.21k
        const auto nEndPos = std::min(nNextPos, mnEndPos);
772
3.21k
        if (mpInputStream->Tell() >= nEndPos)
773
1.16k
            return;
774
2.05k
        if (!mpInputStream->good())
775
0
            return;
776
        //check against numeric overflowing
777
2.05k
        if (nGesPoints >= SAL_MAX_UINT32 / sizeof(Point))
778
308
            return;
779
1.74k
        if (nPoly >= SAL_MAX_UINT32 / sizeof(sal_uInt16))
780
107
            return;
781
1.63k
        if (nPoly * sizeof(sal_uInt16) > nEndPos - mpInputStream->Tell())
782
217
            return;
783
784
        // Get number of points in each polygon
785
1.41k
        std::vector<sal_uInt16> aPoints(nPoly);
786
10.2k
        for (sal_uInt32 i = 0; i < nPoly && mpInputStream->good(); ++i)
787
8.87k
        {
788
8.87k
            sal_uInt32 nPoints(0);
789
8.87k
            mpInputStream->ReadUInt32( nPoints );
790
791
8.87k
            SAL_INFO("emfio", "\t\t\t\tPolygon " << i << " points: " << nPoints);
792
793
8.87k
            aPoints[i] = static_cast<sal_uInt16>(nPoints);
794
8.87k
        }
795
796
1.41k
        if ( mpInputStream->good() && ( nGesPoints * (sizeof(T)+sizeof(T)) ) <= ( nEndPos - mpInputStream->Tell() ) )
797
1.09k
        {
798
            // Get polygon points
799
1.09k
            tools::PolyPolygon aPolyPoly(nPoly);
800
5.87k
            for (sal_uInt32 i = 0; i < nPoly && mpInputStream->good(); ++i)
801
4.78k
            {
802
4.78k
                const sal_uInt16 nPointCount(aPoints[i]);
803
4.78k
                std::vector<Point> aPtAry(nPointCount);
804
689k
                for (sal_uInt16 j = 0; j < nPointCount && mpInputStream->good(); ++j)
805
684k
                {
806
684k
                    T nX(0), nY(0);
807
684k
                    *mpInputStream >> nX >> nY;
808
684k
                    aPtAry[j] = Point( nX, nY );
809
684k
                    ++nReadPoints;
810
684k
                }
811
812
4.78k
                aPolyPoly.Insert(tools::Polygon(aPtAry.size(), aPtAry.data()));
813
4.78k
            }
814
815
1.09k
            DrawPolyPolygon(aPolyPoly, mbRecordPath);
816
1.09k
        }
817
818
1.41k
        OSL_ENSURE(nReadPoints == nGesPoints, "The number Points processed from EMR_POLYPOLYGON is unequal imported number (!)");
819
1.41k
    }
void emfio::EmfReader::ReadAndDrawPolyPolygon<short>(unsigned int)
Line
Count
Source
761
2.04k
    {
762
2.04k
        SAL_INFO("emfio", "\t\tPolygon: ");
763
2.04k
        mpInputStream->SeekRel( 0x10 ); // RectL bounds
764
765
2.04k
        sal_uInt32 nPoly(0), nGesPoints(0), nReadPoints(0);
766
        // Number of polygons
767
2.04k
        mpInputStream->ReadUInt32( nPoly ).ReadUInt32( nGesPoints );
768
2.04k
        SAL_INFO("emfio", "\t\t\tPolygons: " << nPoly);
769
2.04k
        SAL_INFO("emfio", "\t\t\tPoints: " << nGesPoints);
770
771
2.04k
        const auto nEndPos = std::min(nNextPos, mnEndPos);
772
2.04k
        if (mpInputStream->Tell() >= nEndPos)
773
350
            return;
774
1.69k
        if (!mpInputStream->good())
775
0
            return;
776
        //check against numeric overflowing
777
1.69k
        if (nGesPoints >= SAL_MAX_UINT32 / sizeof(Point))
778
109
            return;
779
1.58k
        if (nPoly >= SAL_MAX_UINT32 / sizeof(sal_uInt16))
780
25
            return;
781
1.56k
        if (nPoly * sizeof(sal_uInt16) > nEndPos - mpInputStream->Tell())
782
769
            return;
783
784
        // Get number of points in each polygon
785
794
        std::vector<sal_uInt16> aPoints(nPoly);
786
2.40k
        for (sal_uInt32 i = 0; i < nPoly && mpInputStream->good(); ++i)
787
1.60k
        {
788
1.60k
            sal_uInt32 nPoints(0);
789
1.60k
            mpInputStream->ReadUInt32( nPoints );
790
791
1.60k
            SAL_INFO("emfio", "\t\t\t\tPolygon " << i << " points: " << nPoints);
792
793
1.60k
            aPoints[i] = static_cast<sal_uInt16>(nPoints);
794
1.60k
        }
795
796
794
        if ( mpInputStream->good() && ( nGesPoints * (sizeof(T)+sizeof(T)) ) <= ( nEndPos - mpInputStream->Tell() ) )
797
710
        {
798
            // Get polygon points
799
710
            tools::PolyPolygon aPolyPoly(nPoly);
800
1.67k
            for (sal_uInt32 i = 0; i < nPoly && mpInputStream->good(); ++i)
801
960
            {
802
960
                const sal_uInt16 nPointCount(aPoints[i]);
803
960
                std::vector<Point> aPtAry(nPointCount);
804
601k
                for (sal_uInt16 j = 0; j < nPointCount && mpInputStream->good(); ++j)
805
600k
                {
806
600k
                    T nX(0), nY(0);
807
600k
                    *mpInputStream >> nX >> nY;
808
600k
                    aPtAry[j] = Point( nX, nY );
809
600k
                    ++nReadPoints;
810
600k
                }
811
812
960
                aPolyPoly.Insert(tools::Polygon(aPtAry.size(), aPtAry.data()));
813
960
            }
814
815
710
            DrawPolyPolygon(aPolyPoly, mbRecordPath);
816
710
        }
817
818
794
        OSL_ENSURE(nReadPoints == nGesPoints, "The number Points processed from EMR_POLYPOLYGON is unequal imported number (!)");
819
794
    }
820
821
    bool EmfReader::ReadEnhWMF()
822
8.66k
    {
823
8.66k
        sal_uInt32  nStretchBltMode = 0;
824
8.66k
        sal_uInt32  nNextPos(0),
825
8.66k
                    nW(0), nH(0), nColor(0), nIndex(0),
826
8.66k
                    nDat32(0), nNom1(0), nDen1(0), nNom2(0), nDen2(0);
827
8.66k
        sal_Int32   nX32(0), nY32(0), nx32(0), ny32(0);
828
829
8.66k
        bool    bStatus = ReadHeader();
830
8.66k
        bool    bHaveDC = false;
831
832
8.66k
        OUString aEMFPlusDisable;
833
8.66k
        rtl::Bootstrap::get(u"EMF_PLUS_DISABLE"_ustr, aEMFPlusDisable);
834
8.66k
        bool bEnableEMFPlus = aEMFPlusDisable.isEmpty();
835
8.66k
        if (!mbEnableEMFPlus)
836
0
        {
837
            // EMF+ is enabled if neither the bootstrap variable, not the member variable disables
838
            // it.
839
0
            bEnableEMFPlus = mbEnableEMFPlus;
840
0
        }
841
842
8.66k
        SAL_INFO("emfio", "EMF+ reading is " << (bEnableEMFPlus ? "enabled" : "disabled"));
843
844
343k
        while (bStatus && mnRecordCount-- && mpInputStream->good() && !mbReadOtherGraphicFormat)
845
341k
        {
846
341k
            sal_uInt32  nRecType(0), nRecSize(0);
847
341k
            mpInputStream->ReadUInt32(nRecType).ReadUInt32(nRecSize);
848
849
341k
            if ( !mpInputStream->good() || ( nRecSize < 8 ) || ( nRecSize & 3 ) )     // Parameters are always divisible by 4
850
3.81k
            {
851
3.81k
                bStatus = false;
852
3.81k
                break;
853
3.81k
            }
854
855
337k
            auto nCurPos = mpInputStream->Tell();
856
857
337k
            if (mnEndPos < nCurPos - 8)
858
5
            {
859
5
                bStatus = false;
860
5
                break;
861
5
            }
862
863
337k
            const sal_uInt32 nMaxPossibleRecSize = mnEndPos - (nCurPos - 8);
864
337k
            if (nRecSize > nMaxPossibleRecSize)
865
2.26k
            {
866
2.26k
                bStatus = false;
867
2.26k
                break;
868
2.26k
            }
869
870
335k
            nNextPos = nCurPos + (nRecSize - 8);
871
872
335k
            if(  !maBmpSaveList.empty()
873
37.1k
              && ( nRecType != EMR_STRETCHBLT )
874
32.5k
              && ( nRecType != EMR_STRETCHDIBITS )
875
335k
              ) {
876
23.5k
                ResolveBitmapActions( maBmpSaveList );
877
23.5k
            }
878
879
335k
            bool bFlag = false;
880
881
335k
            SAL_INFO("emfio", "0x" << std::hex << (nNextPos - nRecSize) <<  "-0x" << nNextPos << " " << record_type_name(nRecType) << " size: "
882
335k
                                    << std::dec << nRecSize);
883
884
335k
            if( bEnableEMFPlus && nRecType == EMR_COMMENT )
885
22.6k
            {
886
22.6k
                sal_uInt32 length;
887
888
22.6k
                mpInputStream->ReadUInt32( length );
889
890
22.6k
                SAL_INFO("emfio", "\tGDI comment, length: " << length);
891
892
22.6k
                if( mpInputStream->good() && length >= 4 && length <= mpInputStream->remainingSize() ) {
893
21.8k
                    sal_uInt32 nCommentId;
894
895
21.8k
                    mpInputStream->ReadUInt32( nCommentId );
896
897
21.8k
                    SAL_INFO("emfio", "\t\tbegin " << static_cast<char>(nCommentId & 0xff) << static_cast<char>((nCommentId & 0xff00) >> 8) << static_cast<char>((nCommentId & 0xff0000) >> 16) << static_cast<char>((nCommentId & 0xff000000) >> 24) << " id: 0x" << std::hex << nCommentId << std::dec);
898
899
21.8k
                    if( nCommentId == EMR_COMMENT_EMFPLUS && nRecSize >= 12 )
900
1.21k
                    {
901
                        // [MS-EMF] 2.3.3: DataSize includes both CommentIdentifier and CommentRecordParm fields.
902
                        // We have already read 4-byte CommentIdentifier, so reduce length appropriately
903
1.21k
                        ReadEMFPlusComment( length-4, bHaveDC );
904
1.21k
                    }
905
20.6k
                    else if( nCommentId == EMR_COMMENT_PUBLIC && nRecSize >= 12 )
906
19.1k
                    {
907
19.1k
                        ReadGDIComment(nCommentId);
908
19.1k
                    }
909
1.49k
                    else if( nCommentId == EMR_COMMENT_EMFSPOOL && nRecSize >= 12 )
910
0
                    {
911
0
                        SAL_WARN("emfio", "\t\tEMFSPOOL not implemented, id: 0x" << std::hex << nCommentId << std::dec);
912
                        // TODO Implement reading EMFSPOOL comment
913
914
0
                    }
915
1.49k
                    else
916
1.49k
                    {
917
1.49k
                        SAL_WARN("emfio", "\t\tunknown id: 0x" << std::hex << nCommentId << std::dec);
918
1.49k
                    }
919
21.8k
                }
920
22.6k
            }
921
312k
            else if ( !bHaveDC && mbEMFPlusDualMode && nRecType != EMR_HEADER && nRecType != EMR_EOF )
922
757
            {
923
                // skip content (EMF record) in dual mode
924
                // we process only EMR_COMMENT (see above) to access EMF+ data
925
                // with 2 exceptions, according to EMF+ specification:
926
                // EMR_HEADER and EMR_EOF
927
                // if a device context is given (bHaveDC) process the following EMF record, too.
928
757
            }
929
311k
            else if( !mbEMFPlus || bHaveDC || nRecType == EMR_EOF )
930
311k
            {
931
311k
                switch( nRecType )
932
311k
                {
933
897
                    case EMR_POLYBEZIERTO :
934
897
                        DrawPolyBezier(ReadPolygonWithSkip<sal_Int32>(true, nNextPos), true, mbRecordPath);
935
897
                    break;
936
663
                    case EMR_POLYBEZIER :
937
663
                        DrawPolyBezier(ReadPolygonWithSkip<sal_Int32>(false, nNextPos), false, mbRecordPath);
938
663
                    break;
939
940
2.22k
                    case EMR_POLYGON :
941
2.22k
                        DrawPolygon(ReadPolygonWithSkip<sal_Int32>(false, nNextPos), mbRecordPath);
942
2.22k
                    break;
943
944
2.10k
                    case EMR_POLYLINETO :
945
2.10k
                        DrawPolyLine(ReadPolygonWithSkip<sal_Int32>(true, nNextPos), true, mbRecordPath);
946
2.10k
                    break;
947
948
8.19k
                    case EMR_POLYDRAW:
949
8.19k
                    {
950
8.19k
                        sal_uInt32 nPointsCount(0), nBezierCount(0);
951
8.19k
                        std::vector<Point> aPoints;
952
8.19k
                        bool wrongFile = false;
953
8.19k
                        std::vector<unsigned char> aPointTypes;
954
8.19k
                        mpInputStream->ReadInt32(nX32)
955
8.19k
                            .ReadInt32(nY32)
956
8.19k
                            .ReadInt32(nx32)
957
8.19k
                            .ReadInt32(ny32)
958
8.19k
                            .ReadUInt32(nPointsCount);
959
960
8.19k
                        aPoints.reserve(std::min<size_t>(nPointsCount, mpInputStream->remainingSize() / (sizeof(sal_Int32) * 2)));
961
2.27M
                        for (sal_uInt32 i = 0; i < nPointsCount && mpInputStream->good(); i++)
962
2.26M
                        {
963
2.26M
                            sal_Int32 nX, nY;
964
2.26M
                            *mpInputStream >> nX >> nY;
965
2.26M
                            aPoints.emplace_back(nX, nY);
966
2.26M
                        }
967
8.19k
                        aPointTypes.reserve(std::min<size_t>(nPointsCount, mpInputStream->remainingSize()));
968
657k
                        for (sal_uInt32 i = 0; i < nPointsCount && mpInputStream->good(); i++)
969
649k
                        {
970
649k
                            unsigned char nPointType(0);
971
649k
                            mpInputStream->ReadUChar(nPointType);
972
649k
                            aPointTypes.push_back(nPointType);
973
649k
                        }
974
8.19k
                        nPointsCount = std::min(aPoints.size(), aPointTypes.size());
975
657k
                        for (sal_uInt32 i = 0; i < nPointsCount; i++)
976
649k
                        {
977
649k
                            SAL_INFO_IF(aPointTypes[i] == PT_MOVETO, "emfio",
978
649k
                                        "\t\t" << i << "/" << nPointsCount - 1 << " PT_MOVETO, "
979
649k
                                               << aPoints[i].getX() << ", " << aPoints[i].getY());
980
649k
                            SAL_INFO_IF((aPointTypes[i] != PT_MOVETO) && (aPointTypes[i] & PT_LINETO), "emfio",
981
649k
                                        "\t\t" << i << "/" << nPointsCount - 1 << " PT_LINETO, "
982
649k
                                               << aPoints[i].getX() << ", " << aPoints[i].getY());
983
649k
                            SAL_INFO_IF((aPointTypes[i] != PT_MOVETO) && (aPointTypes[i] & PT_CLOSEFIGURE), "emfio",
984
649k
                                        "\t\t" << i << "/" << nPointsCount - 1 << " PT_CLOSEFIGURE, "
985
649k
                                               << aPoints[i].getX() << ", " << aPoints[i].getY());
986
649k
                            SAL_INFO_IF((aPointTypes[i] != PT_MOVETO) && (aPointTypes[i] & PT_BEZIERTO), "emfio",
987
649k
                                        "\t\t" << i << "/" << nPointsCount - 1 << " PT_BEZIERTO, "
988
649k
                                               << aPoints[i].getX() << ", " << aPoints[i].getY());
989
990
649k
                            if ((aPointTypes[i] != PT_MOVETO) && (aPointTypes[i] & PT_BEZIERTO))
991
273k
                                nBezierCount++;
992
376k
                            else if (nBezierCount % 3 == 0)
993
205k
                                nBezierCount = 0;
994
170k
                            else
995
170k
                            {
996
170k
                                SAL_WARN(
997
170k
                                    "emfio",
998
170k
                                    "EMF file error: Number of Bezier points is not set of three.");
999
170k
                                wrongFile = true;
1000
170k
                            }
1001
649k
                        }
1002
8.19k
                        if (wrongFile) break;
1003
250k
                        for (sal_uInt32 i = 0; i < nPointsCount; i++)
1004
246k
                        {
1005
246k
                            if (aPointTypes[i] == PT_MOVETO)
1006
239
                                MoveTo(aPoints[i], true);
1007
246k
                            else if (aPointTypes[i] & PT_LINETO)
1008
158k
                            {
1009
158k
                                LineTo(aPoints[i], true);
1010
158k
                                if (aPointTypes[i] & PT_CLOSEFIGURE)
1011
156k
                                    ClosePath();
1012
158k
                            }
1013
88.2k
                            else if (aPointTypes[i] & PT_BEZIERTO)
1014
4.80k
                            {
1015
4.80k
                                if (nPointsCount - i < 3)
1016
174
                                {
1017
174
                                    SAL_WARN("emfio", "EMF file error: Not enough Bezier points.");
1018
174
                                    break;
1019
174
                                }
1020
4.63k
                                tools::Polygon aPolygon(4);
1021
4.63k
                                aPolygon[0] = maActPos;
1022
4.63k
                                aPolygon[1] = aPoints[i++];
1023
4.63k
                                aPolygon[2] = aPoints[i++];
1024
4.63k
                                aPolygon[3] = aPoints[i];
1025
4.63k
                                DrawPolyBezier(std::move(aPolygon), true, true);
1026
4.63k
                                if (aPointTypes[i] & PT_CLOSEFIGURE)
1027
3.15k
                                    ClosePath();
1028
4.63k
                            }
1029
246k
                        }
1030
4.57k
                        StrokeAndFillPath(true, false);
1031
4.57k
                    }
1032
0
                    break;
1033
1034
922
                    case EMR_POLYLINE :
1035
922
                        DrawPolyLine(ReadPolygonWithSkip<sal_Int32>(false, nNextPos), false, mbRecordPath);
1036
922
                    break;
1037
1038
1.91k
                    case EMR_POLYPOLYLINE :
1039
1.91k
                        ReadAndDrawPolyLine<sal_Int32>(nNextPos);
1040
1.91k
                    break;
1041
1042
3.21k
                    case EMR_POLYPOLYGON :
1043
3.21k
                        ReadAndDrawPolyPolygon<sal_Int32>(nNextPos);
1044
3.21k
                    break;
1045
1046
1.68k
                    case EMR_SETWINDOWEXTEX :
1047
1.68k
                    {
1048
1.68k
                        sal_Int32 w = 0, h = 0;
1049
1.68k
                        mpInputStream->ReadInt32( w ).ReadInt32( h );
1050
1.68k
                        SAL_INFO("emfio", "\t\tWidth: " << w);
1051
1.68k
                        SAL_INFO("emfio", "\t\tHeight: " << h);
1052
1.68k
                        SetWinExt( Size( w, h ), true);
1053
1.68k
                    }
1054
0
                    break;
1055
1056
3.75k
                    case EMR_SETWINDOWORGEX :
1057
3.75k
                    {
1058
3.75k
                        mpInputStream->ReadInt32( nX32 ).ReadInt32( nY32 );
1059
3.75k
                        SAL_INFO("emfio", "\t\tPoint: (" << nX32 << ", " << nY32 << ")");
1060
3.75k
                        SetWinOrg( Point( nX32, nY32 ), true);
1061
3.75k
                    }
1062
0
                    break;
1063
1064
1.58k
                    case EMR_SCALEWINDOWEXTEX :
1065
1.58k
                    {
1066
1.58k
                        mpInputStream->ReadUInt32( nNom1 ).ReadUInt32( nDen1 ).ReadUInt32( nNom2 ).ReadUInt32( nDen2 );
1067
1.58k
                        SAL_INFO("emfio", "\t\tHorizontal scale: " << nNom1 << " / " << nDen1);
1068
1.58k
                        SAL_INFO("emfio", "\t\tVertical scale: " << nNom2 << " / " << nDen2);
1069
1070
1.58k
                        if (nDen1 != 0 && nDen2 != 0)
1071
783
                            ScaleWinExt( static_cast<double>(nNom1) / nDen1, static_cast<double>(nNom2) / nDen2 );
1072
803
                        else
1073
1.58k
                            SAL_WARN("vcl.emf", "ignoring bogus divide by zero");
1074
1.58k
                    }
1075
1.58k
                    break;
1076
1077
1.58k
                    case EMR_SETVIEWPORTORGEX :
1078
1.13k
                    {
1079
1.13k
                        mpInputStream->ReadInt32( nX32 ).ReadInt32( nY32 );
1080
1.13k
                        SAL_INFO("emfio", "\t\tPoint: (" << nX32 << ", " << nY32 << ")");
1081
1.13k
                        SetDevOrg( Point( nX32, nY32 ) );
1082
1.13k
                    }
1083
0
                    break;
1084
1085
2.00k
                    case EMR_SCALEVIEWPORTEXTEX :
1086
2.00k
                    {
1087
2.00k
                        mpInputStream->ReadUInt32( nNom1 ).ReadUInt32( nDen1 ).ReadUInt32( nNom2 ).ReadUInt32( nDen2 );
1088
2.00k
                        SAL_INFO("emfio", "\t\tHorizontal scale: " << nNom1 << " / " << nDen1);
1089
2.00k
                        SAL_INFO("emfio", "\t\tVertical scale: " << nNom2 << " / " << nDen2);
1090
1091
2.00k
                        if (nDen1 != 0 && nDen2 != 0)
1092
1.89k
                            ScaleDevExt( static_cast<double>(nNom1) / nDen1, static_cast<double>(nNom2) / nDen2 );
1093
103
                        else
1094
2.00k
                            SAL_WARN("vcl.emf", "ignoring bogus divide by zero");
1095
2.00k
                    }
1096
2.00k
                    break;
1097
1098
2.00k
                    case EMR_SETVIEWPORTEXTEX :
1099
1.39k
                    {
1100
1.39k
                        sal_Int32 w = 0, h = 0;
1101
1.39k
                        mpInputStream->ReadInt32( w ).ReadInt32( h );
1102
1.39k
                        SAL_INFO("emfio", "\t\tWidth: " << w);
1103
1.39k
                        SAL_INFO("emfio", "\t\tHeight: " << h);
1104
1105
1.39k
                        SetDevExt( Size( w, h ) );
1106
1.39k
                    }
1107
0
                    break;
1108
1109
20
                    case EMR_EOF :
1110
20
                        mnRecordCount = 0;
1111
20
                    break;
1112
1113
160
                    case EMR_SETPIXELV :
1114
160
                    {
1115
160
                        mpInputStream->ReadInt32( nX32 ).ReadInt32( nY32 );
1116
160
                        SAL_INFO("emfio", "\t\tPoint: (" << nX32 << ", " << nY32 << ")");
1117
160
                        DrawPixel( Point( nX32, nY32 ), ReadColor() );
1118
160
                    }
1119
0
                    break;
1120
1121
2.30k
                    case EMR_SETMAPMODE :
1122
2.30k
                    {
1123
2.30k
                        sal_uInt32 nMapMode(0);
1124
2.30k
                        mpInputStream->ReadUInt32( nMapMode );
1125
2.30k
                        SAL_INFO("emfio", "\t\tMapMode: 0x" << std::hex << nMapMode << std::dec);
1126
2.30k
                        SetMapMode( static_cast<MappingMode>(nMapMode) );
1127
2.30k
                    }
1128
0
                    break;
1129
1130
738
                    case EMR_SETBKMODE :
1131
738
                    {
1132
738
                        mpInputStream->ReadUInt32( nDat32 );
1133
738
                        SAL_INFO("emfio", "\t\tBkMode: 0x" << std::hex << nDat32 << std::dec);
1134
738
                        SetBkMode( static_cast<BackgroundMode>(nDat32) );
1135
738
                    }
1136
0
                    break;
1137
1138
100
                    case EMR_SETPOLYFILLMODE :
1139
100
                    break;
1140
1141
3.32k
                    case EMR_SETROP2 :
1142
3.32k
                    {
1143
3.32k
                        mpInputStream->ReadUInt32( nDat32 );
1144
3.32k
                        SAL_INFO("emfio", "\t\tROP2: 0x" << std::hex << nDat32 << std::dec);
1145
3.32k
                        SetRasterOp( static_cast<WMFRasterOp>(nDat32) );
1146
3.32k
                    }
1147
0
                    break;
1148
1149
567
                    case EMR_SETSTRETCHBLTMODE :
1150
567
                    {
1151
567
                        mpInputStream->ReadUInt32( nStretchBltMode );
1152
567
                        SAL_INFO("emfio", "\t\tStretchBltMode: 0x" << std::hex << nDat32 << std::dec);
1153
567
                    }
1154
567
                    break;
1155
1156
1.75k
                    case EMR_SETTEXTALIGN :
1157
1.75k
                    {
1158
1.75k
                        mpInputStream->ReadUInt32( nDat32 );
1159
1.75k
                        SAL_INFO("emfio", "\t\tTextAlign: 0x" << std::hex << nDat32 << std::dec);
1160
1.75k
                        SetTextAlign( nDat32 );
1161
1.75k
                    }
1162
0
                    break;
1163
1164
2.27k
                    case EMR_SETTEXTCOLOR :
1165
2.27k
                    {
1166
2.27k
                        SetTextColor( ReadColor() );
1167
2.27k
                    }
1168
2.27k
                    break;
1169
1170
396
                    case EMR_SETARCDIRECTION:
1171
396
                    {
1172
396
                        mpInputStream->ReadUInt32(nIndex);
1173
396
                        SetArcDirection(nIndex == ARCDIRECTION_CLOCKWISE);
1174
396
                    }
1175
396
                    break;
1176
1177
2.17k
                    case EMR_SETBKCOLOR :
1178
2.17k
                    {
1179
2.17k
                        SetBkColor( ReadColor() );
1180
2.17k
                    }
1181
2.17k
                    break;
1182
1183
311
                    case EMR_OFFSETCLIPRGN :
1184
311
                    {
1185
311
                        mpInputStream->ReadInt32( nX32 ).ReadInt32( nY32 );
1186
311
                        SAL_INFO("emfio", "\t\tPoint: (" << nX32 << ", " << nY32 << ")");
1187
311
                        MoveClipRegion( Size( nX32, nY32 ) );
1188
311
                    }
1189
0
                    break;
1190
1191
9.88k
                    case EMR_MOVETOEX :
1192
9.88k
                    {
1193
9.88k
                        mpInputStream->ReadInt32( nX32 ).ReadInt32( nY32 );
1194
9.88k
                        SAL_INFO("emfio", "\t\tPoint: (" << nX32 << ", " << nY32 << ")");
1195
9.88k
                        MoveTo( Point( nX32, nY32 ), mbRecordPath);
1196
9.88k
                    }
1197
0
                    break;
1198
1199
1.45k
                    case EMR_INTERSECTCLIPRECT :
1200
1.45k
                    {
1201
1.45k
                        mpInputStream->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 );
1202
1.45k
                        IntersectClipRect( ReadRectangle( nX32, nY32, nx32, ny32 ) );
1203
1.45k
                        SAL_INFO("emfio", "\t\tPoint: (" << nX32 << ", " << nY32 << ")");
1204
1.45k
                        SAL_INFO("emfio", "\t\tPoint: (" << nx32 << ", " << ny32 << ")");
1205
1.45k
                    }
1206
1.45k
                    break;
1207
1208
14.9k
                    case EMR_SAVEDC :
1209
14.9k
                    {
1210
14.9k
                        Push();
1211
14.9k
                    }
1212
14.9k
                    break;
1213
1214
2.12k
                    case EMR_RESTOREDC :
1215
2.12k
                    {
1216
2.12k
                        sal_Int32 nSavedDC(0);
1217
2.12k
                        mpInputStream->ReadInt32( nSavedDC );
1218
2.12k
                        SAL_INFO( "emfio", "\t\t SavedDC Index: " << nSavedDC );
1219
2.12k
                        if ( nSavedDC < 0 )
1220
1.34k
                            Pop( nSavedDC );
1221
780
                        else
1222
780
                            Pop( -1 ); // For RestoreDC values above -1, treat as get last element
1223
2.12k
                    }
1224
0
                    break;
1225
1226
533
                    case EMR_SETWORLDTRANSFORM :
1227
533
                    {
1228
533
                        XForm aTempXForm;
1229
533
                        *mpInputStream >> aTempXForm;
1230
533
                        SetWorldTransform( aTempXForm );
1231
533
                    }
1232
533
                    break;
1233
1234
3.29k
                    case EMR_MODIFYWORLDTRANSFORM :
1235
3.29k
                    {
1236
3.29k
                        sal_uInt32 nMode(0);
1237
3.29k
                        XForm aTempXForm;
1238
3.29k
                        *mpInputStream >> aTempXForm;
1239
3.29k
                        mpInputStream->ReadUInt32( nMode );
1240
3.29k
                        ModifyWorldTransform( aTempXForm, static_cast<ModifyWorldTransformMode>(nMode) );
1241
3.29k
                    }
1242
3.29k
                    break;
1243
1244
14.4k
                    case EMR_SELECTOBJECT :
1245
14.4k
                    {
1246
14.4k
                        mpInputStream->ReadUInt32( nIndex );
1247
14.4k
                        SelectObject( nIndex );
1248
14.4k
                    }
1249
14.4k
                    break;
1250
1251
1.89k
                    case EMR_CREATEPEN:
1252
1.89k
                    {
1253
1.89k
                        mpInputStream->ReadUInt32(nIndex);
1254
1.89k
                        if ((nIndex & ENHMETA_STOCK_OBJECT) == 0)
1255
1.85k
                        {
1256
1.85k
                            sal_uInt32 nPenStyle(0);
1257
1.85k
                            sal_Int32 nPenWidth(0), nIgnored;
1258
1.85k
                            mpInputStream->ReadUInt32(nPenStyle).ReadInt32(nPenWidth).ReadInt32(nIgnored);
1259
1.85k
                            SAL_INFO("emfio", "\t\tIndex: " << nIndex << " Style: 0x" << std::hex
1260
1.85k
                                                            << nPenStyle << std::dec
1261
1.85k
                                                            << " PenWidth: " << nPenWidth);
1262
                            // PS_COSMETIC width is always fixed at one logical unit
1263
                            // and is not affected by any geometric transformations like scaling
1264
1.85k
                            if (nPenStyle == PS_COSMETIC)
1265
304
                                nPenWidth = 1;
1266
1.85k
                            CreateObjectIndexed(nIndex, std::make_unique<WinMtfLineStyle>(ReadColor(), nPenStyle, nPenWidth));
1267
1.85k
                        }
1268
1.89k
                    }
1269
1.89k
                    break;
1270
1271
2.21k
                    case EMR_EXTCREATEPEN:
1272
2.21k
                    {
1273
2.21k
                        mpInputStream->ReadUInt32(nIndex);
1274
2.21k
                        if ((nIndex & ENHMETA_STOCK_OBJECT) == 0)
1275
1.37k
                        {
1276
1.37k
                            sal_uInt32 offBmi, cbBmi, offBits, cbBits, nPenStyle, nWidth, nBrushStyle, elpNumEntries;
1277
1.37k
                            sal_Int32 elpHatch;
1278
1.37k
                            mpInputStream->ReadUInt32(offBmi).ReadUInt32(cbBmi).ReadUInt32(offBits).ReadUInt32(cbBits);
1279
1.37k
                            mpInputStream->ReadUInt32(nPenStyle).ReadUInt32(nWidth).ReadUInt32(nBrushStyle);
1280
1.37k
                            Color aColorRef = ReadColor();
1281
1.37k
                            mpInputStream->ReadInt32(elpHatch).ReadUInt32(elpNumEntries);
1282
1283
1.37k
                            if (!mpInputStream->good())
1284
9
                                bStatus = false;
1285
1.36k
                            else
1286
1.36k
                            {
1287
1.36k
                                SAL_INFO("emfio", "\t\tStyle: 0x" << std::hex << nPenStyle << std::dec);
1288
                                // PS_COSMETIC width is always fixed at one logical unit
1289
                                // and is not affected by any geometric transformations like scaling
1290
1.36k
                                if (nPenStyle == PS_COSMETIC)
1291
145
                                    nWidth = 1;
1292
1.36k
                                SAL_INFO("emfio", "\t\tWidth: " << nWidth);
1293
1.36k
                                CreateObjectIndexed(nIndex, std::make_unique<WinMtfLineStyle>(aColorRef, nPenStyle, nWidth));
1294
1.36k
                            }
1295
1.37k
                        }
1296
2.21k
                    }
1297
2.21k
                    break;
1298
1299
3.82k
                    case EMR_CREATEBRUSHINDIRECT :
1300
3.82k
                    {
1301
3.82k
                        mpInputStream->ReadUInt32( nIndex );
1302
3.82k
                        if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 )
1303
3.40k
                        {
1304
3.40k
                            sal_uInt32  nStyle;
1305
3.40k
                            mpInputStream->ReadUInt32( nStyle );
1306
3.40k
                            BrushStyle eStyle = static_cast<BrushStyle>(nStyle);
1307
3.40k
                            CreateObjectIndexed(nIndex, std::make_unique<WinMtfFillStyle>( ReadColor(), ( eStyle == BrushStyle::BS_HOLLOW ) ));
1308
3.40k
                        }
1309
3.82k
                    }
1310
3.82k
                    break;
1311
1312
5.75k
                    case EMR_DELETEOBJECT :
1313
5.75k
                    {
1314
5.75k
                        mpInputStream->ReadUInt32( nIndex );
1315
5.75k
                        if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 )
1316
4.09k
                            DeleteObject( nIndex );
1317
5.75k
                    }
1318
5.75k
                    break;
1319
1320
2.30k
                    case EMR_ELLIPSE:
1321
2.30k
                    {
1322
2.30k
                        mpInputStream->ReadInt32(nX32).ReadInt32(nY32).ReadInt32(nx32).ReadInt32(ny32);
1323
2.30k
                        SAL_INFO("emfio", "\t\t Rectangle, left: " << nX32 << ", top: " << nY32 << ", right: " << nx32 << ", bottom: " << ny32);
1324
1325
2.30k
                        sal_Int32 w(0), h(0);
1326
2.30k
                        if (o3tl::checked_sub(nx32, nX32, w) || o3tl::checked_sub(ny32, nY32, h))
1327
2.30k
                            SAL_WARN("emfio", "broken ellipse");
1328
2.22k
                        else
1329
2.22k
                        {
1330
2.22k
                            tools::Long dw = w / 2;
1331
2.22k
                            tools::Long dh = h / 2;
1332
2.22k
                            Point aCenter(nX32 + dw, nY32 + dh);
1333
2.22k
                            tools::Polygon aPoly(aCenter, dw, dh);
1334
2.22k
                            DrawPolygon(std::move(aPoly), mbRecordPath);
1335
2.22k
                        }
1336
2.30k
                    }
1337
2.30k
                    break;
1338
1339
2.30k
                    case EMR_RECTANGLE :
1340
564
                    {
1341
564
                        mpInputStream->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 );
1342
564
                        SAL_INFO("emfio", "\t\t Rectangle, left: " << nX32 << ", top: " << nY32 << ", right: " << nx32 << ", bottom: " << ny32);
1343
564
                        Point aPoints[] { Point(nX32, nY32),
1344
564
                                          Point(nx32, nY32),
1345
564
                                          Point(nx32, ny32),
1346
564
                                          Point(nX32, ny32) };
1347
564
                        tools::Polygon aPoly(4, aPoints);
1348
564
                        aPoly.Optimize( PolyOptimizeFlags::CLOSE );
1349
564
                        DrawPolygon( std::move(aPoly), mbRecordPath );
1350
564
                    }
1351
0
                    break;
1352
1353
2.05k
                    case EMR_ROUNDRECT:
1354
2.05k
                    {
1355
2.05k
                        mpInputStream->ReadInt32(nX32).ReadInt32(nY32).ReadInt32(nx32).ReadInt32(ny32).ReadUInt32(nW).ReadUInt32(nH);
1356
2.05k
                        SAL_INFO("emfio", "\t\t Rectangle position: " << nX32 << ":" << nY32 << ", " << nx32 << ":" << ny32);
1357
2.05k
                        SAL_INFO("emfio", "\t\t Ellipse Width: " << nW << ", Height" << nH);
1358
                        // Convert from ellipse width and height to ellipse vertical and horizontal radius
1359
2.05k
                        tools::Polygon aRoundRectPoly(ReadRectangle(nX32, nY32, nx32, ny32), nW >> 1, nH >> 1);
1360
2.05k
                        DrawPolygon(std::move(aRoundRectPoly), mbRecordPath);
1361
2.05k
                    }
1362
0
                    break;
1363
1364
1.67k
                    case EMR_ANGLEARC:
1365
1.67k
                    {
1366
1.67k
                        sal_Int32 nCenterX, nCenterY;
1367
1.67k
                        sal_uInt32 nRadius;
1368
1.67k
                        float fStartAngle, fSweepAngle;
1369
1.67k
                        mpInputStream->ReadInt32(nCenterX).ReadInt32(nCenterY).ReadUInt32(nRadius);
1370
1.67k
                        mpInputStream->ReadFloat(fStartAngle).ReadFloat(fSweepAngle);
1371
1.67k
                        SAL_INFO("emfio", "\t\t Center: " << nCenterX << ":" << nCenterY << ", Radius: " << nRadius);
1372
1.67k
                        SAL_INFO("emfio", "\t\t Start Angle: " << fStartAngle << ", Sweep Angle: " << fSweepAngle);
1373
1374
1.67k
                        if (!mpInputStream->good())
1375
7
                            bStatus = false;
1376
1.67k
                        else
1377
1.67k
                        {
1378
                            // Convert from degrees to radians and start angle to draw from x-axis
1379
1.67k
                            fStartAngle = basegfx::deg2rad(fStartAngle);
1380
1.67k
                            fSweepAngle = basegfx::deg2rad(fSweepAngle);
1381
1382
1.67k
                            tools::Polygon aPoly(Point(nCenterX, nCenterY), nRadius, fStartAngle, fSweepAngle, IsArcDirectionClockWise());
1383
1384
1.67k
                            if (!aPoly.GetSize())
1385
16
                            {
1386
16
                                SAL_WARN("emfio", "EMF file error: 0 points");
1387
16
                            }
1388
1.65k
                            else
1389
1.65k
                            {
1390
                                // Before drawing the arc, AngleArc draws the line segment from the current position to the beginning of the arc
1391
1.65k
                                LineTo(aPoly[0], mbRecordPath);
1392
1.65k
                                DrawPolyLine(std::move(aPoly), true, mbRecordPath);
1393
1.65k
                            }
1394
1.67k
                        }
1395
1.67k
                    }
1396
1.67k
                    break;
1397
1398
1.67k
                    case EMR_ARC :
1399
2.65k
                    case EMR_ARCTO :
1400
3.80k
                    case EMR_CHORD :
1401
3.80k
                    {
1402
3.80k
                        sal_Int32 nStartX, nStartY, nEndX, nEndY;
1403
3.80k
                        mpInputStream->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ).ReadInt32( nStartX ).ReadInt32( nStartY ).ReadInt32( nEndX ).ReadInt32( nEndY );
1404
3.80k
                        if (!mpInputStream->good())
1405
24
                            bStatus = false;
1406
3.78k
                        else
1407
3.78k
                        {
1408
3.78k
                            SAL_INFO( "emfio", "\t\t Bounds: " << nX32 << ":" << nY32 << ", " << nx32 << ":" << ny32 << ", Start: " << nStartX << ":" << nStartY << ", End: " << nEndX << ":" << nEndY );
1409
3.78k
                            tools::Polygon aPoly(ReadRectangle(nX32, nY32, nx32, ny32), Point(nStartX, nStartY), Point(nEndX, nEndY), PolyStyle::Arc, IsArcDirectionClockWise());
1410
1411
3.78k
                            if ( nRecType == EMR_CHORD )
1412
1.14k
                                DrawPolygon( std::move(aPoly), mbRecordPath );
1413
2.63k
                            else
1414
2.63k
                                DrawPolyLine( std::move(aPoly), nRecType == EMR_ARCTO, mbRecordPath );
1415
3.78k
                        }
1416
3.80k
                    }
1417
3.80k
                    break;
1418
1419
3.80k
                    case EMR_PIE :
1420
1.67k
                    {
1421
1.67k
                        sal_Int32 nStartX, nStartY, nEndX, nEndY;
1422
1.67k
                        mpInputStream->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ).ReadInt32( nStartX ).ReadInt32( nStartY ).ReadInt32( nEndX ).ReadInt32( nEndY );
1423
1.67k
                        if (!mpInputStream->good())
1424
21
                            bStatus = false;
1425
1.65k
                        else
1426
1.65k
                        {
1427
1.65k
                            tools::Polygon aPoly(ReadRectangle(nX32, nY32, nx32, ny32), Point(nStartX, nStartY), Point(nEndX, nEndY), PolyStyle::Pie, IsArcDirectionClockWise());
1428
1.65k
                            DrawPolygon( std::move(aPoly), mbRecordPath );
1429
1.65k
                        }
1430
1.67k
                    }
1431
1.67k
                    break;
1432
1433
3.05k
                    case EMR_LINETO :
1434
3.05k
                    {
1435
3.05k
                        mpInputStream->ReadInt32( nX32 ).ReadInt32( nY32 );
1436
3.05k
                        LineTo( Point( nX32, nY32 ), mbRecordPath);
1437
3.05k
                    }
1438
3.05k
                    break;
1439
1440
3.88k
                    case EMR_BEGINPATH :
1441
3.88k
                    {
1442
3.88k
                        ClearPath();
1443
3.88k
                        mbRecordPath = true;
1444
3.88k
                    }
1445
3.88k
                    break;
1446
1447
785
                    case EMR_ABORTPATH :
1448
785
                        ClearPath();
1449
785
                        [[fallthrough]];
1450
1.90k
                    case EMR_ENDPATH :
1451
1.90k
                        mbRecordPath = false;
1452
1.90k
                    break;
1453
1454
577
                    case EMR_CLOSEFIGURE :
1455
577
                        ClosePath();
1456
577
                    break;
1457
1458
1.28k
                    case EMR_FILLPATH :
1459
1.28k
                        StrokeAndFillPath( false, true );
1460
1.28k
                    break;
1461
1462
1.53k
                    case EMR_STROKEANDFILLPATH :
1463
1.53k
                        StrokeAndFillPath( true, true );
1464
1.53k
                    break;
1465
1466
871
                    case EMR_STROKEPATH :
1467
871
                        StrokeAndFillPath( true, false );
1468
871
                    break;
1469
1470
101
                    case EMR_SELECTCLIPPATH :
1471
101
                    {
1472
101
                        sal_Int32 nClippingMode(0);
1473
101
                        mpInputStream->ReadInt32(nClippingMode);
1474
101
                        SetClipPath(GetPathObj(), static_cast<RegionMode>(nClippingMode), true);
1475
101
                    }
1476
101
                    break;
1477
1478
1.38k
                    case EMR_EXTSELECTCLIPRGN :
1479
1.38k
                    {
1480
1.38k
                        sal_uInt32 nRemainingRecSize = nRecSize - 8;
1481
1.38k
                        if (nRemainingRecSize < 8)
1482
2
                            bStatus = false;
1483
1.38k
                        else
1484
1.38k
                        {
1485
1.38k
                            sal_Int32 nClippingMode(0), cbRgnData(0);
1486
1.38k
                            mpInputStream->ReadInt32(cbRgnData);
1487
1.38k
                            mpInputStream->ReadInt32(nClippingMode);
1488
1.38k
                            nRemainingRecSize -= 8;
1489
1490
                            // This record's region data should be ignored if mode
1491
                            // is RGN_COPY - see EMF spec section 2.3.2.2
1492
1.38k
                            if (static_cast<RegionMode>(nClippingMode) == RegionMode::RGN_COPY)
1493
797
                            {
1494
797
                                SetDefaultClipPath();
1495
797
                            }
1496
589
                            else
1497
589
                            {
1498
589
                                basegfx::B2DPolyPolygon aPolyPoly;
1499
589
                                if (cbRgnData)
1500
520
                                    ImplReadRegion(aPolyPoly, *mpInputStream, nRemainingRecSize, GetWinOrg());
1501
589
                                const tools::PolyPolygon aPolyPolygon(aPolyPoly);
1502
589
                                SetClipPath(aPolyPolygon, static_cast<RegionMode>(nClippingMode), false);
1503
589
                            }
1504
1.38k
                        }
1505
1.38k
                    }
1506
1.38k
                    break;
1507
1508
12.9k
                    case EMR_ALPHABLEND:
1509
12.9k
                    {
1510
12.9k
                        sal_Int32 xDest(0), yDest(0), cxDest(0), cyDest(0);
1511
1512
12.9k
                        BLENDFUNCTION aFunc;
1513
12.9k
                        sal_Int32 xSrc(0), ySrc(0), cxSrc(0), cySrc(0);
1514
12.9k
                        XForm xformSrc;
1515
12.9k
                        sal_uInt32 BkColorSrc(0), iUsageSrc(0), offBmiSrc(0);
1516
12.9k
                        sal_uInt32 cbBmiSrc(0), offBitsSrc(0), cbBitsSrc(0);
1517
1518
12.9k
                        sal_uInt64   nStart = mpInputStream->Tell() - 8;
1519
12.9k
                        mpInputStream->SeekRel( 0x10 );
1520
1521
12.9k
                        mpInputStream->ReadInt32( xDest ).ReadInt32( yDest ).ReadInt32( cxDest ).ReadInt32( cyDest );
1522
12.9k
                        *mpInputStream >> aFunc;
1523
12.9k
                        mpInputStream->ReadInt32( xSrc ).ReadInt32( ySrc );
1524
12.9k
                        *mpInputStream >> xformSrc;
1525
12.9k
                        mpInputStream->ReadUInt32( BkColorSrc ).ReadUInt32( iUsageSrc ).ReadUInt32( offBmiSrc ).ReadUInt32( cbBmiSrc )
1526
12.9k
                                   .ReadUInt32( offBitsSrc ).ReadUInt32( cbBitsSrc ).ReadInt32( cxSrc ).ReadInt32( cySrc ) ;
1527
1528
12.9k
                        if ( !mpInputStream->good() ||
1529
12.8k
                             (cbBitsSrc > (SAL_MAX_UINT32 - 14)) ||
1530
12.8k
                             ((SAL_MAX_UINT32 - 14) - cbBitsSrc < cbBmiSrc) ||
1531
12.8k
                             cxDest == SAL_MAX_INT32 || cyDest == SAL_MAX_INT32 )
1532
152
                        {
1533
152
                            bStatus = false;
1534
152
                        }
1535
12.8k
                        else
1536
12.8k
                        {
1537
12.8k
                            tools::Rectangle aRect(Point(xDest, yDest), Size(cxDest + 1, cyDest + 1));
1538
1539
12.8k
                            const sal_uInt32 nSourceSize = cbBmiSrc + cbBitsSrc + 14;
1540
12.8k
                            bool bSafeRead = nSourceSize <= (mnEndPos - mnStartPos);
1541
12.8k
                            sal_uInt32 nDeltaToDIB5HeaderSize(0);
1542
12.8k
                            const bool bReadAlpha(0x01 == aFunc.aAlphaFormat);
1543
12.8k
                            if (bSafeRead && bReadAlpha)
1544
3.20k
                            {
1545
                                // we need to read alpha channel data if AlphaFormat of BLENDFUNCTION is
1546
                                // AC_SRC_ALPHA (==0x01). To read it, create a temp DIB-File which is ready
1547
                                // for DIB-5 format
1548
3.20k
                                const sal_uInt32 nHeaderSize = getDIBV5HeaderSize();
1549
3.20k
                                if (cbBmiSrc > nHeaderSize)
1550
56
                                    bSafeRead = false;
1551
3.15k
                                else
1552
3.15k
                                    nDeltaToDIB5HeaderSize = nHeaderSize - cbBmiSrc;
1553
3.20k
                            }
1554
12.8k
                            if (bSafeRead)
1555
10.2k
                            {
1556
10.2k
                                const sal_uInt32 nTargetSize(cbBmiSrc + nDeltaToDIB5HeaderSize + cbBitsSrc + 14);
1557
10.2k
                                char* pBuf = new char[ nTargetSize ];
1558
10.2k
                                SvMemoryStream aTmp( pBuf, nTargetSize, StreamMode::READ | StreamMode::WRITE );
1559
1560
10.2k
                                aTmp.ObjectOwnsMemory( true );
1561
1562
                                // write BM-Header (14 bytes)
1563
10.2k
                                aTmp.WriteUChar( 'B' )
1564
10.2k
                                    .WriteUChar( 'M' )
1565
10.2k
                                    .WriteUInt32( cbBitsSrc )
1566
10.2k
                                    .WriteUInt16( 0 )
1567
10.2k
                                    .WriteUInt16( 0 )
1568
10.2k
                                    .WriteUInt32( cbBmiSrc + nDeltaToDIB5HeaderSize + 14 );
1569
1570
                                // copy DIBInfoHeader from source (cbBmiSrc bytes)
1571
10.2k
                                mpInputStream->Seek( nStart + offBmiSrc );
1572
10.2k
                                char* pWritePos = pBuf + 14;
1573
10.2k
                                auto nRead = mpInputStream->ReadBytes(pWritePos, cbBmiSrc);
1574
10.2k
                                if (nRead != cbBmiSrc)
1575
221
                                {
1576
                                    // zero remainder if short read
1577
221
                                    memset(pWritePos + nRead, 0, cbBmiSrc - nRead);
1578
221
                                }
1579
1580
10.2k
                                if (bReadAlpha)
1581
3.15k
                                {
1582
                                    // need to add values for all stuff that DIBV5Header is bigger
1583
                                    // than DIBInfoHeader, all values are correctly initialized to zero,
1584
                                    // so we can use memset here
1585
3.15k
                                    memset(pBuf + cbBmiSrc + 14, 0, nDeltaToDIB5HeaderSize);
1586
3.15k
                                }
1587
1588
                                // copy bitmap data from source (offBitsSrc bytes)
1589
10.2k
                                mpInputStream->Seek( nStart + offBitsSrc );
1590
10.2k
                                pWritePos = pBuf + 14 + nDeltaToDIB5HeaderSize + cbBmiSrc;
1591
10.2k
                                nRead = mpInputStream->ReadBytes(pWritePos, cbBitsSrc);
1592
10.2k
                                if (nRead != cbBitsSrc)
1593
232
                                {
1594
                                    // zero remainder if short read
1595
232
                                    memset(pWritePos + nRead, 0, cbBitsSrc - nRead);
1596
232
                                }
1597
1598
10.2k
                                aTmp.Seek( 0 );
1599
1600
                                // prepare to read and fill Bitmap
1601
10.2k
                                Bitmap aBitmapEx;
1602
1603
10.2k
                                if(bReadAlpha)
1604
3.15k
                                {
1605
3.15k
                                    Bitmap aBitmap;
1606
3.15k
                                    AlphaMask aAlpha;
1607
1608
3.15k
                                    if(ReadDIBV5(aBitmap, aAlpha, aTmp))
1609
1.61k
                                    {
1610
1.61k
                                        aBitmapEx = Bitmap(aBitmap, aAlpha);
1611
1.61k
                                    }
1612
3.15k
                                }
1613
7.12k
                                else
1614
7.12k
                                {
1615
7.12k
                                    Bitmap aBitmap;
1616
1617
7.12k
                                    if(ReadDIB(aBitmap, aTmp, true))
1618
2.48k
                                    {
1619
2.48k
                                        if(0xff != aFunc.aSrcConstantAlpha)
1620
1.45k
                                        {
1621
                                            // add const alpha channel
1622
1.45k
                                            aBitmapEx = Bitmap(
1623
1.45k
                                                aBitmap,
1624
1.45k
                                                AlphaMask(aBitmap.GetSizePixel(), &aFunc.aSrcConstantAlpha));
1625
1.45k
                                        }
1626
1.02k
                                        else
1627
1.02k
                                        {
1628
                                            // just use Bitmap
1629
1.02k
                                            aBitmapEx = std::move(aBitmap);
1630
1.02k
                                        }
1631
2.48k
                                    }
1632
7.12k
                                }
1633
1634
10.2k
                                if(!aBitmapEx.IsEmpty())
1635
4.09k
                                {
1636
                                    // test if it is sensible to crop
1637
4.09k
                                    if (cxSrc > 0 && cySrc > 0 && xSrc >= 0 && ySrc >= 0)
1638
2.50k
                                    {
1639
2.50k
                                        sal_Int32 xEndSrc;
1640
2.50k
                                        sal_Int32 yEndSrc;
1641
2.50k
                                        if (!o3tl::checked_add(xSrc, cxSrc, xEndSrc) && xEndSrc < aBitmapEx.GetSizePixel().Width() &&
1642
941
                                            !o3tl::checked_add(ySrc, cySrc, yEndSrc) && yEndSrc < aBitmapEx.GetSizePixel().Height())
1643
90
                                        {
1644
90
                                            const tools::Rectangle aCropRect( Point( xSrc, ySrc ), Size( cxSrc, cySrc ) );
1645
90
                                            aBitmapEx.Crop( aCropRect );
1646
90
                                        }
1647
2.50k
                                    }
1648
1649
#ifdef DBG_UTIL
1650
                                    static bool bDoSaveForVisualControl(false); // loplugin:constvars:ignore
1651
1652
                                    if(bDoSaveForVisualControl)
1653
                                    {
1654
                                        // VCL_DUMP_BMP_PATH should be like C:/path/ or ~/path/
1655
                                        static const OUString sDumpPath(o3tl::getEnvironment(u"VCL_DUMP_BMP_PATH"_ustr));
1656
                                        if(!sDumpPath.isEmpty())
1657
                                        {
1658
                                            SvFileStream aNew(sDumpPath + "metafile_content.png",
1659
                                                            StreamMode::WRITE | StreamMode::TRUNC);
1660
                                            vcl::PngImageWriter aPNGWriter(aNew);
1661
                                            aPNGWriter.write(aBitmapEx);
1662
                                        }
1663
                                    }
1664
#endif
1665
4.09k
                                    maBmpSaveList.emplace_back(aBitmapEx, aRect, SRCAND|SRCINVERT);
1666
4.09k
                                }
1667
10.2k
                            }
1668
12.8k
                        }
1669
12.9k
                    }
1670
12.9k
                    break;
1671
1672
15.0k
                    case EMR_BITBLT :   // PASSTHROUGH INTENDED
1673
27.1k
                    case EMR_STRETCHBLT :
1674
27.1k
                    {
1675
27.1k
                        sal_Int32   xDest, yDest, cxDest, cyDest, xSrc, ySrc, cxSrc, cySrc;
1676
27.1k
                        sal_uInt32  dwRop, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc;
1677
27.1k
                        XForm   xformSrc;
1678
1679
27.1k
                        sal_uInt64  nStart = mpInputStream->Tell() - 8;
1680
1681
27.1k
                        mpInputStream->SeekRel( 0x10 );
1682
27.1k
                        mpInputStream->ReadInt32( xDest ).ReadInt32( yDest ).ReadInt32( cxDest ).ReadInt32( cyDest ).ReadUInt32( dwRop ).ReadInt32( xSrc ).ReadInt32( ySrc )
1683
27.1k
                                >> xformSrc;
1684
27.1k
                        mpInputStream->ReadUInt32( nColor ).ReadUInt32( iUsageSrc ).ReadUInt32( offBmiSrc ).ReadUInt32( cbBmiSrc )
1685
27.1k
                                   .ReadUInt32( offBitsSrc ).ReadUInt32( cbBitsSrc );
1686
1687
27.1k
                        if ( nRecType == EMR_STRETCHBLT )
1688
12.1k
                            mpInputStream->ReadInt32( cxSrc ).ReadInt32( cySrc );
1689
15.0k
                        else
1690
15.0k
                            cxSrc = cySrc = 0;
1691
1692
27.1k
                        if (!mpInputStream->good() || (cbBitsSrc > (SAL_MAX_UINT32 - 14)) || ((SAL_MAX_UINT32 - 14) - cbBitsSrc < cbBmiSrc))
1693
151
                            bStatus = false;
1694
27.0k
                        else
1695
27.0k
                        {
1696
27.0k
                            Bitmap aBitmap;
1697
27.0k
                            tools::Rectangle aRect(Point(xDest, yDest), Size(cxDest, cyDest));
1698
1699
27.0k
                            sal_uInt32 nSize = cbBmiSrc + cbBitsSrc + 14;
1700
27.0k
                            if ( nSize <= ( mnEndPos - mnStartPos ) )
1701
20.9k
                            {
1702
20.9k
                                char* pBuf = new char[ nSize ];
1703
20.9k
                                SvMemoryStream aTmp( pBuf, nSize, StreamMode::READ | StreamMode::WRITE );
1704
20.9k
                                aTmp.ObjectOwnsMemory( true );
1705
20.9k
                                aTmp.WriteUChar( 'B' )
1706
20.9k
                                    .WriteUChar( 'M' )
1707
20.9k
                                    .WriteUInt32( cbBitsSrc )
1708
20.9k
                                    .WriteUInt16( 0 )
1709
20.9k
                                    .WriteUInt16( 0 )
1710
20.9k
                                    .WriteUInt32( cbBmiSrc + 14 );
1711
1712
20.9k
                                mpInputStream->Seek( nStart + offBmiSrc );
1713
20.9k
                                char* pWritePos = pBuf + 14;
1714
20.9k
                                auto nRead = mpInputStream->ReadBytes(pWritePos, cbBmiSrc);
1715
20.9k
                                if (nRead != cbBmiSrc)
1716
384
                                {
1717
                                    // zero remainder if short read
1718
384
                                    memset(pWritePos + nRead, 0, cbBmiSrc - nRead);
1719
384
                                }
1720
1721
20.9k
                                mpInputStream->Seek( nStart + offBitsSrc );
1722
20.9k
                                pWritePos = pBuf + 14 + cbBmiSrc;
1723
20.9k
                                nRead = mpInputStream->ReadBytes(pWritePos, cbBitsSrc);
1724
20.9k
                                if (nRead != cbBitsSrc)
1725
428
                                {
1726
                                    // zero remainder if short read
1727
428
                                    memset(pWritePos + nRead, 0, cbBitsSrc - nRead);
1728
428
                                }
1729
1730
20.9k
                                aTmp.Seek( 0 );
1731
20.9k
                                ReadDIB(aBitmap, aTmp, true);
1732
1733
                                // test if it is sensible to crop
1734
20.9k
                                if ( (cxSrc > 0) && (cySrc > 0) &&
1735
7.48k
                                     (xSrc >= 0) && (ySrc >= 0) &&
1736
6.13k
                                     (aBitmap.GetSizePixel().Width() >= cxSrc) &&
1737
1.12k
                                     (xSrc <= aBitmap.GetSizePixel().Width() - cxSrc) &&
1738
533
                                     (aBitmap.GetSizePixel().Height() >= cySrc) &&
1739
503
                                     (ySrc <= aBitmap.GetSizePixel().Height() - cySrc) )
1740
475
                                {
1741
475
                                    tools::Rectangle aCropRect( Point( xSrc, ySrc ), Size( cxSrc, cySrc ) );
1742
475
                                    aBitmap.Crop( aCropRect );
1743
475
                                }
1744
1745
20.9k
                                maBmpSaveList.emplace_back(aBitmap, aRect, dwRop);
1746
20.9k
                            }
1747
27.0k
                        }
1748
27.1k
                    }
1749
27.1k
                    break;
1750
1751
13.1k
                    case EMR_STRETCHDIBITS :
1752
13.1k
                    {
1753
13.1k
                        sal_Int32   xDest, yDest, xSrc, ySrc, cxSrc, cySrc, cxDest, cyDest;
1754
13.1k
                        sal_uInt32  offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, iUsageSrc, dwRop;
1755
13.1k
                        sal_uInt64  nStart = mpInputStream->Tell() - 8;
1756
1757
13.1k
                        mpInputStream->SeekRel( 0x10 );
1758
13.1k
                        mpInputStream->ReadInt32( xDest )
1759
13.1k
                             .ReadInt32( yDest )
1760
13.1k
                             .ReadInt32( xSrc )
1761
13.1k
                             .ReadInt32( ySrc )
1762
13.1k
                             .ReadInt32( cxSrc )
1763
13.1k
                             .ReadInt32( cySrc )
1764
13.1k
                             .ReadUInt32( offBmiSrc )
1765
13.1k
                             .ReadUInt32( cbBmiSrc )
1766
13.1k
                             .ReadUInt32( offBitsSrc )
1767
13.1k
                             .ReadUInt32( cbBitsSrc )
1768
13.1k
                             .ReadUInt32( iUsageSrc )
1769
13.1k
                             .ReadUInt32( dwRop )
1770
13.1k
                             .ReadInt32( cxDest )
1771
13.1k
                             .ReadInt32( cyDest );
1772
1773
13.1k
                        if (!mpInputStream->good() ||
1774
13.0k
                            ((SAL_MAX_UINT32 - 14) < cbBitsSrc) ||
1775
13.0k
                            ((SAL_MAX_UINT32 - 14) - cbBitsSrc < cbBmiSrc))
1776
182
                        {
1777
182
                            bStatus = false;
1778
182
                        }
1779
13.0k
                        else
1780
13.0k
                        {
1781
13.0k
                            Bitmap aBitmap;
1782
13.0k
                            tools::Rectangle aRect(xDest, yDest);
1783
13.0k
                            aRect.SaturatingSetSize(Size(cxDest, cyDest));
1784
1785
13.0k
                            sal_uInt32 nSize = cbBmiSrc + cbBitsSrc + 14;
1786
13.0k
                            if ( nSize <= ( mnEndPos - mnStartPos ) )
1787
11.4k
                            {
1788
11.4k
                                char* pBuf = new char[ nSize ];
1789
11.4k
                                SvMemoryStream aTmp( pBuf, nSize, StreamMode::READ | StreamMode::WRITE );
1790
11.4k
                                aTmp.ObjectOwnsMemory( true );
1791
11.4k
                                aTmp.WriteUChar( 'B' )
1792
11.4k
                                   .WriteUChar( 'M' )
1793
11.4k
                                   .WriteUInt32( cbBitsSrc )
1794
11.4k
                                   .WriteUInt16( 0 )
1795
11.4k
                                   .WriteUInt16( 0 )
1796
11.4k
                                   .WriteUInt32( cbBmiSrc + 14 );
1797
1798
11.4k
                                mpInputStream->Seek( nStart + offBmiSrc );
1799
11.4k
                                char* pWritePos = pBuf + 14;
1800
11.4k
                                auto nRead = mpInputStream->ReadBytes(pWritePos, cbBmiSrc);
1801
11.4k
                                if (nRead != cbBmiSrc)
1802
405
                                {
1803
                                    // zero remainder if short read
1804
405
                                    memset(pWritePos + nRead, 0, cbBmiSrc - nRead);
1805
405
                                }
1806
1807
11.4k
                                mpInputStream->Seek( nStart + offBitsSrc );
1808
11.4k
                                pWritePos = pBuf + 14 + cbBmiSrc;
1809
11.4k
                                nRead = mpInputStream->ReadBytes(pWritePos, cbBitsSrc);
1810
11.4k
                                if (nRead != cbBitsSrc)
1811
523
                                {
1812
                                    // zero remainder if short read
1813
523
                                    memset(pWritePos + nRead, 0, cbBitsSrc - nRead);
1814
523
                                }
1815
1816
11.4k
                                aTmp.Seek( 0 );
1817
11.4k
                                ReadDIB(aBitmap, aTmp, true);
1818
1819
11.4k
                                const tools::Long nWidthDiff = aBitmap.GetSizePixel().Width() - cxSrc;
1820
11.4k
                                const tools::Long nHeightDiff = aBitmap.GetSizePixel().Height() - cySrc;
1821
1822
                                // test if it is sensible to crop
1823
11.4k
                                if ( (cxSrc > 0) && (cySrc > 0) &&
1824
9.17k
                                     (xSrc >= 0) && (ySrc >= 0) &&
1825
8.34k
                                     (xSrc <= nWidthDiff) && (ySrc <= nHeightDiff) )
1826
333
                                {
1827
333
                                    tools::Rectangle aCropRect( Point( xSrc, ySrc ), Size( cxSrc, cySrc ) );
1828
333
                                    aBitmap.Crop( aCropRect );
1829
333
                                }
1830
11.4k
                                maBmpSaveList.emplace_back(aBitmap, aRect, dwRop);
1831
11.4k
                            }
1832
13.0k
                        }
1833
13.1k
                    }
1834
13.1k
                    break;
1835
1836
3.99k
                    case EMR_EXTCREATEFONTINDIRECTW :
1837
3.99k
                    {
1838
3.99k
                        mpInputStream->ReadUInt32( nIndex );
1839
3.99k
                        if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 )
1840
3.84k
                        {
1841
3.84k
                            LOGFONTW aLogFont;
1842
3.84k
                            mpInputStream->ReadInt32( aLogFont.lfHeight )
1843
3.84k
                                 .ReadInt32( aLogFont.lfWidth )
1844
3.84k
                                 .ReadInt32( aLogFont.lfEscapement )
1845
3.84k
                                 .ReadInt32( aLogFont.lfOrientation )
1846
3.84k
                                 .ReadInt32( aLogFont.lfWeight )
1847
3.84k
                                 .ReadUChar( aLogFont.lfItalic )
1848
3.84k
                                 .ReadUChar( aLogFont.lfUnderline )
1849
3.84k
                                 .ReadUChar( aLogFont.lfStrikeOut )
1850
3.84k
                                 .ReadUChar( aLogFont.lfCharSet )
1851
3.84k
                                 .ReadUChar( aLogFont.lfOutPrecision )
1852
3.84k
                                 .ReadUChar( aLogFont.lfClipPrecision )
1853
3.84k
                                 .ReadUChar( aLogFont.lfQuality )
1854
3.84k
                                 .ReadUChar( aLogFont.lfPitchAndFamily );
1855
1856
3.84k
                            sal_Unicode lfFaceName[LF_FACESIZE+1];
1857
3.84k
                            lfFaceName[LF_FACESIZE] = 0;
1858
126k
                            for (int i = 0; i < LF_FACESIZE; ++i)
1859
122k
                            {
1860
122k
                                sal_uInt16 nChar(0);
1861
122k
                                mpInputStream->ReadUInt16(nChar);
1862
122k
                                lfFaceName[i] = nChar;
1863
122k
                            }
1864
3.84k
                            aLogFont.alfFaceName = OUString( lfFaceName );
1865
1866
                            // #i123216# Not used in the test case of #121382# (always identity in XForm), also
1867
                            // no hints in ms docu if FontSize should be scaled with WT. Using with the example
1868
                            // from #i123216# creates errors, so removing.
1869
1870
                            // // #i121382# Need to apply WorldTransform to FontHeight/Width; this should be completely
1871
                            // // changed to basegfx::B2DHomMatrix instead of 'struct XForm', but not now due to time
1872
                            // // constraints and dangers
1873
                            // const XForm& rXF = GetWorldTransform();
1874
                            // const basegfx::B2DHomMatrix aWT(rXF.eM11, rXF.eM21, rXF.eDx, rXF.eM12, rXF.eM22, rXF.eDy);
1875
                            // const basegfx::B2DVector aTransVec(aWT * basegfx::B2DVector(aLogFont.lfWidth, aLogFont.lfHeight));
1876
                            // aLogFont.lfWidth = aTransVec.getX();
1877
                            // aLogFont.lfHeight = aTransVec.getY();
1878
3.84k
                            if (mpInputStream->good() && aLogFont.lfHeight != SAL_MIN_INT32 && aLogFont.lfWidth != SAL_MIN_INT32)
1879
3.51k
                            {
1880
3.51k
                                CreateObjectIndexed(nIndex, std::make_unique<WinMtfFontStyle>( aLogFont ));
1881
3.51k
                            }
1882
3.84k
                        }
1883
3.99k
                    }
1884
3.99k
                    break;
1885
1886
8.66k
                    case EMR_POLYTEXTOUTA :
1887
10.7k
                    case EMR_EXTTEXTOUTA :
1888
10.7k
                        bFlag = true;
1889
10.7k
                        [[fallthrough]];
1890
12.9k
                    case EMR_POLYTEXTOUTW :
1891
20.1k
                    case EMR_EXTTEXTOUTW :
1892
20.1k
                    {
1893
20.1k
                        sal_Int32   nLeft, nTop, nRight, nBottom;
1894
20.1k
                        sal_uInt32  nGfxMode;
1895
20.1k
                        float       nXScale, nYScale;
1896
20.1k
                        sal_uInt32  ncStrings( 1 );
1897
20.1k
                        sal_Int32   ptlReferenceX, ptlReferenceY;
1898
20.1k
                        sal_uInt32  nLen, nOffString, nOptions, offDx;
1899
20.1k
                        sal_Int32   nLeftRect, nTopRect, nRightRect, nBottomRect;
1900
1901
20.1k
                        nCurPos = mpInputStream->Tell() - 8;
1902
1903
20.1k
                        mpInputStream->ReadInt32( nLeft ).ReadInt32( nTop ).ReadInt32( nRight ).ReadInt32( nBottom )
1904
20.1k
                           .ReadUInt32( nGfxMode ).ReadFloat( nXScale ).ReadFloat( nYScale );
1905
20.1k
                        SAL_INFO("emfio", "\t\tBounds: " << nLeft << ", " << nTop << ", " << nRight << ", " << nBottom);
1906
20.1k
                        SAL_INFO("emfio", "\t\tiGraphicsMode: 0x" << std::hex << nGfxMode << std::dec);
1907
20.1k
                        SAL_INFO("emfio", "\t\t Scale: " << nXScale << " x " << nYScale);
1908
20.1k
                        if ( ( nRecType == EMR_POLYTEXTOUTA ) || ( nRecType == EMR_POLYTEXTOUTW ) )
1909
10.9k
                        {
1910
10.9k
                            mpInputStream->ReadUInt32( ncStrings );
1911
10.9k
                            SAL_INFO("emfio", "\t\t Number of Text objects: " << ncStrings);
1912
10.9k
                            if ( ncStrings == 0 )
1913
760
                                break;
1914
10.9k
                        }
1915
19.3k
                        mpInputStream->ReadInt32( ptlReferenceX ).ReadInt32( ptlReferenceY ).ReadUInt32( nLen ).ReadUInt32( nOffString ).ReadUInt32( nOptions );
1916
19.3k
                        SAL_INFO("emfio", "\t\tReference: (" << ptlReferenceX << ", " << ptlReferenceY << ")");
1917
1918
19.3k
                        mpInputStream->ReadInt32( nLeftRect ).ReadInt32( nTopRect ).ReadInt32( nRightRect ).ReadInt32( nBottomRect );
1919
19.3k
                        mpInputStream->ReadUInt32( offDx );
1920
1921
19.3k
                        if (!mpInputStream->good())
1922
143
                            bStatus = false;
1923
19.2k
                        else
1924
19.2k
                        {
1925
19.2k
                            const tools::Rectangle aRect( nLeftRect, nTopRect, nRightRect, nBottomRect );
1926
19.2k
                            const BackgroundMode mnBkModeBackup = mnBkMode;
1927
19.2k
                            if ( nOptions & ETO_NO_RECT ) // Don't draw the background rectangle and text background
1928
3.18k
                                mnBkMode = BackgroundMode::Transparent;
1929
16.0k
                            else if ( nOptions & ETO_OPAQUE )
1930
2.34k
                                DrawRectWithBGColor( aRect );
1931
1932
                            // ETO_RTLREADING indicates that the characters are laid from right to left
1933
19.2k
                            vcl::text::ComplexTextLayoutFlags nTextLayoutMode = vcl::text::ComplexTextLayoutFlags::Default;
1934
19.2k
                            if ( nOptions & ETO_RTLREADING )
1935
1.93k
                                nTextLayoutMode = vcl::text::ComplexTextLayoutFlags::BiDiRtl | vcl::text::ComplexTextLayoutFlags::TextOriginLeft;
1936
19.2k
                            SetTextLayoutMode( nTextLayoutMode );
1937
19.2k
                            SAL_WARN_IF( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) != 0, "emfio", "SJ: ETO_PDY || ETO_GLYPH_INDEX in EMF" );
1938
1939
19.2k
                            Point aPos( ptlReferenceX, ptlReferenceY );
1940
19.2k
                            bool bOffStringSane = nOffString <= mnEndPos - nCurPos;
1941
19.2k
                            if ( bOffStringSane )
1942
17.0k
                            {
1943
17.0k
                                mpInputStream->Seek( nCurPos + nOffString );
1944
17.0k
                                OUString aText;
1945
17.0k
                                if ( bFlag )
1946
9.06k
                                {
1947
9.06k
                                    if ( nLen <= ( mnEndPos - mpInputStream->Tell() ) )
1948
6.80k
                                    {
1949
6.80k
                                        std::vector<char> pBuf( nLen );
1950
6.80k
                                        mpInputStream->ReadBytes(pBuf.data(), nLen);
1951
6.80k
                                        aText = OUString(pBuf.data(), nLen, GetCharSet());
1952
6.80k
                                    }
1953
9.06k
                                }
1954
7.94k
                                else
1955
7.94k
                                {
1956
7.94k
                                    if ( ( nLen * sizeof(sal_Unicode) ) <= ( mnEndPos - mpInputStream->Tell() ) )
1957
5.95k
                                    {
1958
5.95k
                                        aText = read_uInt16s_ToOUString(*mpInputStream, nLen);
1959
5.95k
                                    }
1960
7.94k
                                }
1961
1962
17.0k
                                SAL_INFO("emfio", "\t\tText: " << aText);
1963
17.0k
                                SAL_INFO("emfio", "\t\tDxBuffer:");
1964
1965
17.0k
                                KernArray aDXAry;
1966
17.0k
                                std::unique_ptr<tools::Long[]> pDYAry;
1967
1968
17.0k
                                sal_Int32 nDxSize;
1969
17.0k
                                sal_Int32 nBytesEach;
1970
1971
                                // Reading OutputDx
1972
                                // ETO_PDY flag indicates that we should read twice values
1973
                                // compared to the number of characters in the output string.
1974
                                // Values are stored in an array of 32-bit unsigned integers
1975
                                // named OutputDx, so there will be either 8 bytes or 4 bytes
1976
                                // each depending on ETO_PDY is set or not.
1977
17.0k
                                if (nOptions & ETO_PDY)
1978
1.42k
                                    nBytesEach = 8;
1979
15.5k
                                else
1980
15.5k
                                    nBytesEach = 4;
1981
1982
17.0k
                                bool bOverflow = o3tl::checked_multiply<sal_Int32>(nLen, nBytesEach, nDxSize);
1983
17.0k
                                if (!bOverflow && offDx && ((nCurPos + offDx + nDxSize) <= nNextPos ) && nNextPos <= mnEndPos)
1984
3.61k
                                {
1985
3.61k
                                    mpInputStream->Seek( nCurPos + offDx );
1986
3.61k
                                    aDXAry.resize(aText.getLength());
1987
3.61k
                                    if (nOptions & ETO_PDY)
1988
635
                                    {
1989
635
                                        pDYAry.reset( new tools::Long[aText.getLength()] );
1990
635
                                    }
1991
1992
28.4k
                                    for (sal_Int32 i = 0; i < aText.getLength(); ++i)
1993
24.8k
                                    {
1994
24.8k
                                        sal_Int32 nDxCount = 1;
1995
24.8k
                                        if ( static_cast<sal_uInt32>( aText.getLength() ) !=  nLen )
1996
8.46k
                                        {
1997
8.46k
                                            sal_Unicode cUniChar = aText[i];
1998
8.46k
                                            OString aTmp(&cUniChar, 1, GetCharSet());
1999
8.46k
                                            if (aTmp.getLength() > 1)
2000
3.78k
                                            {
2001
3.78k
                                                nDxCount = aTmp.getLength();
2002
3.78k
                                            }
2003
8.46k
                                        }
2004
2005
24.8k
                                        aDXAry[i] = 0;
2006
24.8k
                                        if (nOptions & ETO_PDY)
2007
1.92k
                                        {
2008
1.92k
                                            pDYAry[i] = 0;
2009
1.92k
                                        }
2010
2011
53.4k
                                        while (nDxCount--)
2012
28.6k
                                        {
2013
28.6k
                                            sal_Int32 nDxTmp = 0;
2014
28.6k
                                            mpInputStream->ReadInt32(nDxTmp);
2015
28.6k
                                            aDXAry[i] += nDxTmp;
2016
28.6k
                                            if (nOptions & ETO_PDY)
2017
1.92k
                                            {
2018
1.92k
                                                sal_Int32 nDyTmp = 0;
2019
1.92k
                                                mpInputStream->ReadInt32(nDyTmp);
2020
1.92k
                                                pDYAry[i] += nDyTmp;
2021
1.92k
                                            }
2022
28.6k
                                        }
2023
2024
24.8k
                                        SAL_INFO("emfio", "\t\t\tSpacing " << i << ": " << aDXAry[i]);
2025
24.8k
                                    }
2026
3.61k
                                }
2027
17.0k
                                if ( nOptions & ETO_CLIPPED )
2028
6.43k
                                {
2029
6.43k
                                    Push(); // Save the current clip. It will be restored after text drawing
2030
6.43k
                                    IntersectClipRect( aRect );
2031
6.43k
                                }
2032
17.0k
                                DrawText(aPos, aText, aDXAry.empty() ? nullptr : &aDXAry, pDYAry.get(), mbRecordPath, static_cast<GraphicsMode>(nGfxMode));
2033
17.0k
                                if ( nOptions & ETO_CLIPPED )
2034
6.33k
                                    Pop();
2035
17.0k
                            }
2036
19.2k
                            mnBkMode = mnBkModeBackup;
2037
19.2k
                        }
2038
19.3k
                    }
2039
19.3k
                    break;
2040
2041
19.3k
                    case EMR_POLYBEZIERTO16 :
2042
1.84k
                        DrawPolyBezier(ReadPolygonWithSkip<sal_Int16>(true, nNextPos), true, mbRecordPath);
2043
1.84k
                    break;
2044
2045
1.18k
                    case EMR_POLYBEZIER16 :
2046
1.18k
                        DrawPolyBezier(ReadPolygonWithSkip<sal_Int16>(false, nNextPos), false, mbRecordPath);
2047
1.18k
                    break;
2048
2049
18.5k
                    case EMR_POLYGON16 :
2050
18.5k
                        DrawPolygon(ReadPolygonWithSkip<sal_Int16>(false, nNextPos), mbRecordPath);
2051
18.5k
                    break;
2052
2053
1.10k
                    case EMR_POLYLINETO16 :
2054
1.10k
                        DrawPolyLine(ReadPolygonWithSkip<sal_Int16>(true, nNextPos), true, mbRecordPath);
2055
1.10k
                    break;
2056
2057
200
                    case EMR_POLYLINE16 :
2058
200
                        DrawPolyLine(ReadPolygonWithSkip<sal_Int16>(false, nNextPos), false, mbRecordPath);
2059
200
                    break;
2060
2061
661
                    case EMR_POLYPOLYLINE16 :
2062
661
                        ReadAndDrawPolyLine<sal_Int16>(nNextPos);
2063
661
                    break;
2064
2065
2.04k
                    case EMR_POLYPOLYGON16 :
2066
2.04k
                        ReadAndDrawPolyPolygon<sal_Int16>(nNextPos);
2067
2.04k
                    break;
2068
2069
1.00k
                    case EMR_FILLRGN :
2070
1.00k
                    {
2071
1.00k
                        sal_uInt32 nRemainingRecSize = nRecSize - 8;
2072
1.00k
                        if (nRemainingRecSize < 24)
2073
3
                            bStatus = false;
2074
1.00k
                        else
2075
1.00k
                        {
2076
1.00k
                            sal_uInt32 nRgnDataSize;
2077
1.00k
                            basegfx::B2DPolyPolygon aPolyPoly;
2078
1.00k
                            mpInputStream->SeekRel(16);  // RectL bounds
2079
1.00k
                            mpInputStream->ReadUInt32( nRgnDataSize ).ReadUInt32( nIndex );
2080
1.00k
                            nRemainingRecSize -= 24;
2081
2082
1.00k
                            if (ImplReadRegion(aPolyPoly, *mpInputStream, nRemainingRecSize, GetWinOrg()))
2083
460
                            {
2084
460
                                Push();
2085
460
                                SelectObject( nIndex );
2086
460
                                tools::PolyPolygon aPolyPolygon(aPolyPoly);
2087
460
                                DrawPolyPolygon( aPolyPolygon );
2088
460
                                Pop();
2089
460
                            }
2090
1.00k
                        }
2091
1.00k
                    }
2092
1.00k
                    break;
2093
2094
671
                    case EMR_PAINTRGN :
2095
671
                    {
2096
671
                        sal_uInt32 nRemainingRecSize = nRecSize - 8;
2097
671
                        if (nRemainingRecSize < 20)
2098
3
                            bStatus = false;
2099
668
                        else
2100
668
                        {
2101
668
                            sal_uInt32 nRgnDataSize;
2102
668
                            basegfx::B2DPolyPolygon aPolyPoly;
2103
668
                            mpInputStream->SeekRel(16); // Skipping RectL bounds
2104
668
                            mpInputStream->ReadUInt32( nRgnDataSize );
2105
668
                            nRemainingRecSize -= 20;
2106
2107
668
                            if (ImplReadRegion(aPolyPoly, *mpInputStream, nRemainingRecSize, GetWinOrg()))
2108
325
                            {
2109
325
                                tools::PolyPolygon aPolyPolygon(aPolyPoly);
2110
325
                                DrawPolyPolygon( aPolyPolygon );
2111
325
                            }
2112
668
                        }
2113
671
                    }
2114
671
                    break;
2115
2116
11.8k
                    case EMR_CREATEDIBPATTERNBRUSHPT :
2117
11.8k
                    {
2118
11.8k
                        sal_uInt64  nStart = mpInputStream->Tell() - 8;
2119
11.8k
                        Bitmap aBitmap;
2120
2121
11.8k
                        mpInputStream->ReadUInt32( nIndex );
2122
2123
11.8k
                        if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 )
2124
11.6k
                        {
2125
11.6k
                            sal_uInt32 usage, offBmi, cbBmi, offBits, cbBits;
2126
2127
11.6k
                            mpInputStream->ReadUInt32( usage );
2128
11.6k
                            mpInputStream->ReadUInt32( offBmi );
2129
11.6k
                            mpInputStream->ReadUInt32( cbBmi );
2130
11.6k
                            mpInputStream->ReadUInt32( offBits );
2131
11.6k
                            mpInputStream->ReadUInt32( cbBits );
2132
2133
11.6k
                            if ( !mpInputStream->good() || (cbBits > (SAL_MAX_UINT32 - 14)) || ((SAL_MAX_UINT32 - 14) - cbBits < cbBmi) )
2134
11
                               bStatus = false;
2135
11.5k
                            else if ( offBmi )
2136
11.3k
                            {
2137
11.3k
                                sal_uInt32  nSize = cbBmi + cbBits + 14;
2138
11.3k
                                if ( nSize <= ( mnEndPos - mnStartPos ) )
2139
8.65k
                                {
2140
8.65k
                                    char*   pBuf = new char[ nSize ];
2141
2142
8.65k
                                    SvMemoryStream aTmp( pBuf, nSize, StreamMode::READ | StreamMode::WRITE );
2143
8.65k
                                    aTmp.ObjectOwnsMemory( true );
2144
8.65k
                                    aTmp.WriteUChar( 'B' )
2145
8.65k
                                        .WriteUChar( 'M' )
2146
8.65k
                                        .WriteUInt32( cbBits )
2147
8.65k
                                        .WriteUInt16( 0 )
2148
8.65k
                                        .WriteUInt16( 0 )
2149
8.65k
                                        .WriteUInt32( cbBmi + 14 );
2150
2151
8.65k
                                    mpInputStream->Seek( nStart + offBmi );
2152
8.65k
                                    char* pWritePos = pBuf + 14;
2153
8.65k
                                    auto nRead = mpInputStream->ReadBytes(pWritePos, cbBmi);
2154
8.65k
                                    if (nRead != cbBmi)
2155
1.11k
                                    {
2156
                                        // zero remainder if short read
2157
1.11k
                                        memset(pWritePos + nRead, 0, cbBmi - nRead);
2158
1.11k
                                    }
2159
2160
8.65k
                                    mpInputStream->Seek( nStart + offBits );
2161
8.65k
                                    pWritePos = pBuf + 14 + cbBmi;
2162
8.65k
                                    nRead = mpInputStream->ReadBytes(pWritePos, cbBits);
2163
8.65k
                                    if (nRead != cbBits)
2164
720
                                    {
2165
                                        // zero remainder if short read
2166
720
                                        memset(pWritePos + nRead, 0, cbBits - nRead);
2167
720
                                    }
2168
2169
8.65k
                                    aTmp.Seek( 0 );
2170
8.65k
                                    ReadDIB(aBitmap, aTmp, true);
2171
8.65k
                                }
2172
11.3k
                            }
2173
11.6k
                        }
2174
2175
11.8k
                        CreateObjectIndexed(nIndex, std::make_unique<WinMtfFillStyle>( aBitmap ));
2176
11.8k
                    }
2177
11.8k
                    break;
2178
2179
151
                    case EMR_CREATECOLORSPACE :
2180
151
                    {
2181
151
                        sal_uInt32 nRemainingRecSize = nRecSize - 8;
2182
151
                        if (nRemainingRecSize < 5)
2183
1
                            bStatus = false;
2184
150
                        else
2185
150
                        {
2186
                            // index of the logical color space object in the EMF object table
2187
150
                            sal_Int32 ihCS(0);
2188
150
                            mpInputStream->ReadInt32(ihCS);
2189
150
                            sal_Int32 nDescChars = nRemainingRecSize - 4;
2190
150
                            OUStringBuffer aDesc;
2191
2.19k
                            for (sal_Int32 i=0; i < nDescChars; i++)
2192
2.11k
                            {
2193
2.11k
                                unsigned char cChar(0);
2194
2.11k
                                mpInputStream->ReadUChar(cChar);
2195
2.11k
                                if (cChar == 0)
2196
73
                                    break;
2197
2.04k
                                aDesc.append(OUStringChar(static_cast<sal_Unicode>(cChar)));
2198
2.04k
                            }
2199
                            // if it's the standard color space name, no need to do anything
2200
150
                            if (std::u16string_view(aDesc) != u"COSP")
2201
150
                                SAL_WARN("emfio", "TODO: color space change for EMR_CREATECOLORSPACE not implemented: '" << aDesc.toString() << "' " << nDescChars);
2202
150
                        }
2203
151
                    }
2204
151
                    break;
2205
2206
220
                    case EMR_MASKBLT :
2207
328
                    case EMR_PLGBLT :
2208
334
                    case EMR_SETDIBITSTODEVICE :
2209
336
                    case EMR_FRAMERGN :
2210
414
                    case EMR_INVERTRGN :
2211
531
                    case EMR_FLATTENPATH :
2212
534
                    case EMR_WIDENPATH :
2213
947
                    case EMR_SETPALETTEENTRIES :
2214
1.16k
                    case EMR_RESIZEPALETTE :
2215
1.25k
                    case EMR_EXTFLOODFILL :
2216
1.25k
                    case EMR_SETCOLORADJUSTMENT :
2217
1.74k
                    case EMR_POLYDRAW16 :
2218
1.74k
                    case EMR_SETCOLORSPACE :
2219
1.75k
                    case EMR_DELETECOLORSPACE :
2220
1.76k
                    case EMR_GLSRECORD :
2221
1.77k
                    case EMR_GLSBOUNDEDRECORD :
2222
1.79k
                    case EMR_PIXELFORMAT :
2223
1.89k
                    case EMR_DRAWESCAPE :
2224
1.89k
                    case EMR_EXTESCAPE :
2225
1.90k
                    case EMR_STARTDOC :
2226
1.90k
                    case EMR_SMALLTEXTOUT :
2227
1.93k
                    case EMR_FORCEUFIMAPPING :
2228
1.93k
                    case EMR_NAMEDESCAPE :
2229
1.93k
                    case EMR_COLORCORRECTPALETTE :
2230
1.94k
                    case EMR_SETICMPROFILEA :
2231
2.00k
                    case EMR_SETICMPROFILEW :
2232
2.00k
                    case EMR_TRANSPARENTBLT :
2233
2.00k
                    case EMR_TRANSPARENTDIB :
2234
2.01k
                    case EMR_GRADIENTFILL :
2235
2.01k
                    case EMR_SETLINKEDUFIS :
2236
2.02k
                    case EMR_SETMAPPERFLAGS :
2237
2.05k
                    case EMR_SETICMMODE :
2238
2.12k
                    case EMR_CREATEMONOBRUSH :
2239
2.13k
                    case EMR_SETBRUSHORGEX :
2240
2.13k
                    case EMR_SETMETARGN :
2241
2.15k
                    case EMR_SETMITERLIMIT :
2242
2.21k
                    case EMR_EXCLUDECLIPRECT :
2243
2.35k
                    case EMR_REALIZEPALETTE :
2244
2.51k
                    case EMR_SELECTPALETTE :
2245
2.67k
                    case EMR_CREATEPALETTE :
2246
2.68k
                    case EMR_ALPHADIBBLEND :
2247
2.68k
                    case EMR_SETTEXTJUSTIFICATION :
2248
2.68k
                    {
2249
2.68k
                        SAL_WARN("emfio", "TODO: EMF record not implemented: " << record_type_name(nRecType));
2250
2.68k
                    }
2251
2.68k
                    break;
2252
2253
2.68k
                    case EMR_COMMENT :
2254
11.4k
                    case EMR_HEADER :               // has already been read at ReadHeader()
2255
11.4k
                    break;
2256
2257
47.8k
                    default :                           SAL_INFO("emfio", "Unknown Meta Action");                                     break;
2258
311k
                }
2259
311k
            }
2260
334k
            mpInputStream->Seek( nNextPos );
2261
334k
        }
2262
2263
        // tdf#127471
2264
8.28k
        maScaledFontHelper.applyAlternativeFontScale();
2265
2266
8.28k
        if( !maBmpSaveList.empty() )
2267
1.42k
            ResolveBitmapActions( maBmpSaveList );
2268
2269
8.28k
        if ( bStatus )
2270
1.44k
            mpInputStream->Seek(mnEndPos);
2271
2272
8.28k
        return bStatus;
2273
8.66k
    };
2274
2275
    bool EmfReader::ReadHeader()
2276
8.66k
    {
2277
        // Spare me the METAFILEHEADER here
2278
        // Reading the METAHEADER - EMR_HEADER ([MS-EMF] section 2.3.4.2 EMR_HEADER Record Types)
2279
8.66k
        sal_uInt32 nType(0), nHeaderSize(0);
2280
8.66k
        mpInputStream->ReadUInt32(nType).ReadUInt32(nHeaderSize);
2281
8.66k
        SAL_INFO ("emfio", "0x0-0x" << std::hex << nHeaderSize << " " << record_type_name(nType) << " size: " << std::dec <<  nHeaderSize);
2282
8.66k
        if (nType != 0x00000001)
2283
28
        {
2284
            // per [MS-EMF] 2.3.4.2 EMF Header Record Types, type MUST be 0x00000001
2285
28
            SAL_WARN("emfio", "EMF header type is not set to 0x00000001 - possibly corrupted file?");
2286
28
            return false;
2287
28
        }
2288
2289
        // Start reading the EMR_HEADER Header object
2290
2291
        // bound size (RectL object, see [MS-WMF] section 2.2.2.19)
2292
8.64k
        SAL_INFO("emfio", "\tBounding rectangle");
2293
8.64k
        tools::Rectangle rclBounds = ReadRectangle(); // rectangle in logical units
2294
2295
        // picture frame size (RectL object)
2296
8.64k
        SAL_INFO("emfio", "\tPicture frame");
2297
8.64k
        tools::Rectangle rclFrame = ReadRectangle(); // rectangle in device units 1/100th mm
2298
2299
8.64k
        sal_uInt32 nSignature(0);
2300
8.64k
        mpInputStream->ReadUInt32(nSignature);
2301
8.64k
        SAL_INFO("emfio", "\tSignature: 0x" << std::hex << nSignature << std::dec);
2302
2303
        // nSignature MUST be the ASCII characters "FME", see [WS-EMF] 2.2.9 Header Object
2304
        // and 2.1.14 FormatSignature Enumeration
2305
8.64k
        if (nSignature != 0x464d4520)
2306
21
        {
2307
21
            SAL_WARN("emfio", "EMF\t\tSignature is not 0x464d4520 (\"FME\") - possibly corrupted file?");
2308
21
            return false;
2309
21
        }
2310
2311
8.61k
        sal_uInt32 nVersion(0);
2312
8.61k
        mpInputStream->ReadUInt32(nVersion);  // according to [WS-EMF] 2.2.9, this SHOULD be 0x0001000, however
2313
                                       // Microsoft note that not even Windows checks this...
2314
8.61k
        SAL_INFO("emfio", "\tVersion: 0x" << std::hex << nVersion << std::dec);
2315
8.61k
        if (nVersion != 0x00010000)
2316
8.41k
        {
2317
8.41k
            SAL_WARN("emfio", "EMF\t\tThis really should be 0x00010000, though not absolutely essential...");
2318
8.41k
        }
2319
2320
8.61k
        mpInputStream->ReadUInt32(mnEndPos); // size of metafile
2321
8.61k
        SAL_INFO("emfio", "\tMetafile size: " << mnEndPos);
2322
8.61k
        mnEndPos += mnStartPos;
2323
2324
8.61k
        sal_uInt64 nStrmPos = mpInputStream->Tell(); // checking if mnEndPos is valid
2325
8.61k
        sal_uInt64 nActualFileSize = nStrmPos + mpInputStream->remainingSize();
2326
2327
8.61k
        if ( nActualFileSize < mnEndPos )
2328
8.39k
        {
2329
8.39k
            SAL_WARN("emfio", "EMF\t\tEMF Header object records number of bytes as " << mnEndPos
2330
8.39k
                                << ", however the file size is actually " << nActualFileSize
2331
8.39k
                                << " bytes. Possible file corruption?");
2332
8.39k
            mnEndPos = nActualFileSize;
2333
8.39k
        }
2334
2335
8.61k
        mpInputStream->ReadUInt32(mnRecordCount);
2336
8.61k
        SAL_INFO("emfio", "\tRecords: " << mnRecordCount);
2337
2338
        // the number of "handles", or graphics objects used in the metafile
2339
2340
8.61k
        sal_uInt16 nHandlesCount;
2341
8.61k
        mpInputStream->ReadUInt16(nHandlesCount);
2342
8.61k
        SAL_INFO("emfio", "\tGraphics: " << nHandlesCount);
2343
2344
        // the next 2 bytes are reserved, but according to [MS-EMF] section 2.2.9
2345
        // it MUST be 0x000 and MUST be ignored... the thing is, having such a specific
2346
        // value is actually pretty useful in checking if there is possible corruption
2347
2348
8.61k
        sal_uInt16 nReserved(0);
2349
8.61k
        mpInputStream->ReadUInt16(nReserved);
2350
8.61k
        SAL_INFO("emfio", "\tReserved: 0x" << std::hex << nReserved << std::dec);
2351
2352
8.61k
        if ( nReserved != 0x0000 )
2353
3.41k
        {
2354
3.41k
            SAL_WARN("emfio", "EMF\t\tEMF Header object's reserved field is NOT 0x0000... possible "
2355
3.41k
                                "corruption?");
2356
3.41k
        }
2357
2358
        // The next 4 bytes specifies the number of characters in the metafile description.
2359
        // The 4 bytes after that specific the offset from this record that contains the
2360
        // metafile description... zero means no description string.
2361
        // For now, we ignore it.
2362
2363
8.61k
        mpInputStream->SeekRel(0x8);
2364
2365
8.61k
        sal_uInt32 nPalEntries(0);
2366
8.61k
        mpInputStream->ReadUInt32(nPalEntries);
2367
8.61k
        SAL_INFO("emfio", "\tPalette entries: " << nPalEntries);
2368
8.61k
        sal_Int32 nPixX(0), nPixY(0), nMillX(0), nMillY(0);
2369
8.61k
        mpInputStream->ReadInt32(nPixX);
2370
8.61k
        mpInputStream->ReadInt32(nPixY);
2371
8.61k
        SAL_INFO("emfio", "\tRef (pixels): " << nPixX << ", " << nPixY);
2372
8.61k
        mpInputStream->ReadInt32(nMillX);
2373
8.61k
        mpInputStream->ReadInt32(nMillY);
2374
8.61k
        SAL_INFO("emfio", "\tRef (mm): " << nMillX << ", " << nMillY);
2375
2376
8.61k
        SetrclFrame(rclFrame);
2377
8.61k
        SetrclBounds(rclBounds);
2378
8.61k
        SetRefPix(Size( nPixX, nPixY ) );
2379
8.61k
        SetRefMill(Size( nMillX, nMillY ) );
2380
2381
8.61k
        return checkSeek(*mpInputStream, mnStartPos + nHeaderSize);
2382
8.61k
    }
2383
2384
    tools::Rectangle EmfReader::ReadRectangle()
2385
35.2k
    {
2386
35.2k
        sal_Int32 nLeft(0), nTop(0), nRight(0), nBottom(0);
2387
35.2k
        mpInputStream->ReadInt32(nLeft);
2388
35.2k
        mpInputStream->ReadInt32(nTop);
2389
35.2k
        mpInputStream->ReadInt32(nRight);
2390
35.2k
        mpInputStream->ReadInt32(nBottom);
2391
2392
35.2k
        SAL_INFO("emfio", "\t\tLeft: " << nLeft << ", top: " << nTop << ", right: " << nRight << ", bottom: " << nBottom);
2393
35.2k
        if (nLeft > nRight || nTop > nBottom)
2394
26.9k
        {
2395
26.9k
            SAL_WARN("emfio", "broken rectangle");
2396
26.9k
            return tools::Rectangle::Normalize(Point(nLeft, nTop), Point(nRight, nBottom));
2397
26.9k
        }
2398
2399
8.33k
        return tools::Rectangle(nLeft, nTop, nRight, nBottom);
2400
35.2k
    }
2401
2402
    tools::Rectangle EmfReader::ReadRectangle( sal_Int32 x1, sal_Int32 y1, sal_Int32 x2, sal_Int32 y2 )
2403
8.93k
    {
2404
8.93k
        Point aTL(x1, y1);
2405
8.93k
        Point aBR(o3tl::saturating_add<sal_Int32>(x2, -1), o3tl::saturating_add<sal_Int32>(y2, -1));
2406
8.93k
        return tools::Rectangle(aTL, aBR);
2407
8.93k
    }
2408
}
2409
2410
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */