Coverage Report

Created: 2026-11-06 11:29

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