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