Coverage Report

Created: 2026-05-16 09:25

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