Line data Source code
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 "winmtf.hxx"
21 : #include <boost/scoped_array.hpp>
22 : #include <vcl/gdimtf.hxx>
23 : #include <vcl/wmf.hxx>
24 : #include <rtl/crc.h>
25 : #include <rtl/tencinfo.h>
26 : #include <osl/endian.h>
27 : #include <vcl/svapp.hxx>
28 : #include <vcl/dibtools.hxx>
29 : #include <boost/scoped_array.hpp>
30 :
31 : // MS Windows defines
32 :
33 : #define W_META_SETBKCOLOR 0x0201
34 : #define W_META_SETBKMODE 0x0102
35 : #define W_META_SETMAPMODE 0x0103
36 : #define W_META_SETROP2 0x0104
37 : #define W_META_SETRELABS 0x0105
38 : #define W_META_SETPOLYFILLMODE 0x0106
39 : #define W_META_SETSTRETCHBLTMODE 0x0107
40 : #define W_META_SETTEXTCHAREXTRA 0x0108
41 : #define W_META_SETTEXTCOLOR 0x0209
42 : #define W_META_SETTEXTJUSTIFICATION 0x020A
43 : #define W_META_SETWINDOWORG 0x020B
44 : #define W_META_SETWINDOWEXT 0x020C
45 : #define W_META_SETVIEWPORTORG 0x020D
46 : #define W_META_SETVIEWPORTEXT 0x020E
47 : #define W_META_OFFSETWINDOWORG 0x020F
48 : #define W_META_SCALEWINDOWEXT 0x0410
49 : #define W_META_OFFSETVIEWPORTORG 0x0211
50 : #define W_META_SCALEVIEWPORTEXT 0x0412
51 : #define W_META_LINETO 0x0213
52 : #define W_META_MOVETO 0x0214
53 : #define W_META_EXCLUDECLIPRECT 0x0415
54 : #define W_META_INTERSECTCLIPRECT 0x0416
55 : #define W_META_ARC 0x0817
56 : #define W_META_ELLIPSE 0x0418
57 : #define W_META_FLOODFILL 0x0419
58 : #define W_META_PIE 0x081A
59 : #define W_META_RECTANGLE 0x041B
60 : #define W_META_ROUNDRECT 0x061C
61 : #define W_META_PATBLT 0x061D
62 : #define W_META_SAVEDC 0x001E
63 : #define W_META_SETPIXEL 0x041F
64 : #define W_META_OFFSETCLIPRGN 0x0220
65 : #define W_META_TEXTOUT 0x0521
66 : #define W_META_BITBLT 0x0922
67 : #define W_META_STRETCHBLT 0x0B23
68 : #define W_META_POLYGON 0x0324
69 : #define W_META_POLYLINE 0x0325
70 : #define W_META_ESCAPE 0x0626
71 : #define W_META_RESTOREDC 0x0127
72 : #define W_META_FILLREGION 0x0228
73 : #define W_META_FRAMEREGION 0x0429
74 : #define W_META_INVERTREGION 0x012A
75 : #define W_META_PAINTREGION 0x012B
76 : #define W_META_SELECTCLIPREGION 0x012C
77 : #define W_META_SELECTOBJECT 0x012D
78 : #define W_META_SETTEXTALIGN 0x012E
79 : #define W_META_DRAWTEXT 0x062F
80 : #define W_META_CHORD 0x0830
81 : #define W_META_SETMAPPERFLAGS 0x0231
82 : #define W_META_EXTTEXTOUT 0x0a32
83 : #define W_META_SETDIBTODEV 0x0d33
84 : #define W_META_SELECTPALETTE 0x0234
85 : #define W_META_REALIZEPALETTE 0x0035
86 : #define W_META_ANIMATEPALETTE 0x0436
87 : #define W_META_SETPALENTRIES 0x0037
88 : #define W_META_POLYPOLYGON 0x0538
89 : #define W_META_RESIZEPALETTE 0x0139
90 : #define W_META_DIBBITBLT 0x0940
91 : #define W_META_DIBSTRETCHBLT 0x0b41
92 : #define W_META_DIBCREATEPATTERNBRUSH 0x0142
93 : #define W_META_STRETCHDIB 0x0f43
94 : #define W_META_EXTFLOODFILL 0x0548
95 : #define W_META_RESETDC 0x014C
96 : #define W_META_STARTDOC 0x014D
97 : #define W_META_STARTPAGE 0x004F
98 : #define W_META_ENDPAGE 0x0050
99 : #define W_META_ABORTDOC 0x0052
100 : #define W_META_ENDDOC 0x005E
101 : #define W_META_DELETEOBJECT 0x01f0
102 : #define W_META_CREATEPALETTE 0x00f7
103 : #define W_META_CREATEBRUSH 0x00F8
104 : #define W_META_CREATEPATTERNBRUSH 0x01F9
105 : #define W_META_CREATEPENINDIRECT 0x02FA
106 : #define W_META_CREATEFONTINDIRECT 0x02FB
107 : #define W_META_CREATEBRUSHINDIRECT 0x02FC
108 : #define W_META_CREATEBITMAPINDIRECT 0x02FD
109 : #define W_META_CREATEBITMAP 0x06FE
110 : #define W_META_CREATEREGION 0x06FF
111 :
112 0 : static void GetWinExtMax( const Point& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode )
113 : {
114 0 : Point aSource( rSource );
115 0 : if ( nMapMode == MM_HIMETRIC )
116 0 : aSource.Y() = -rSource.Y();
117 0 : if ( aSource.X() < rPlaceableBound.Left() )
118 0 : rPlaceableBound.Left() = aSource.X();
119 0 : if ( aSource.X() > rPlaceableBound.Right() )
120 0 : rPlaceableBound.Right() = aSource.X();
121 0 : if ( aSource.Y() < rPlaceableBound.Top() )
122 0 : rPlaceableBound.Top() = aSource.Y();
123 0 : if ( aSource.Y() > rPlaceableBound.Bottom() )
124 0 : rPlaceableBound.Bottom() = aSource.Y();
125 0 : }
126 :
127 0 : static void GetWinExtMax( const Rectangle& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode )
128 : {
129 0 : GetWinExtMax( rSource.TopLeft(), rPlaceableBound, nMapMode );
130 0 : GetWinExtMax( rSource.BottomRight(), rPlaceableBound, nMapMode );
131 0 : }
132 :
133 0 : inline Point WMFReader::ReadPoint()
134 : {
135 0 : short nX = 0, nY = 0;
136 0 : pWMF->ReadInt16( nX ).ReadInt16( nY );
137 0 : return Point( nX, nY );
138 : }
139 :
140 0 : inline Point WMFReader::ReadYX()
141 : {
142 0 : short nX = 0, nY = 0;
143 0 : pWMF->ReadInt16( nY ).ReadInt16( nX );
144 0 : return Point( nX, nY );
145 : }
146 :
147 0 : Rectangle WMFReader::ReadRectangle()
148 : {
149 0 : Point aBR, aTL;
150 0 : aBR = ReadYX();
151 0 : aTL = ReadYX();
152 0 : aBR.X()--;
153 0 : aBR.Y()--;
154 0 : return Rectangle( aTL, aBR );
155 : }
156 :
157 0 : Size WMFReader::ReadYXExt()
158 : {
159 0 : short nW=0, nH=0;
160 0 : pWMF->ReadInt16( nH ).ReadInt16( nW );
161 0 : return Size( nW, nH );
162 : }
163 :
164 0 : void WMFReader::ReadRecordParams( sal_uInt16 nFunc )
165 : {
166 0 : switch( nFunc )
167 : {
168 : case W_META_SETBKCOLOR:
169 : {
170 0 : pOut->SetBkColor( ReadColor() );
171 : }
172 0 : break;
173 :
174 : case W_META_SETBKMODE:
175 : {
176 0 : sal_uInt16 nDat = 0;
177 0 : pWMF->ReadUInt16( nDat );
178 0 : pOut->SetBkMode( nDat );
179 : }
180 0 : break;
181 :
182 : // !!!
183 : case W_META_SETMAPMODE:
184 : {
185 0 : sal_Int16 nMapMode = 0;
186 0 : pWMF->ReadInt16( nMapMode );
187 0 : pOut->SetMapMode( nMapMode );
188 : }
189 0 : break;
190 :
191 : case W_META_SETROP2:
192 : {
193 0 : sal_uInt16 nROP2 = 0;
194 0 : pWMF->ReadUInt16( nROP2 );
195 0 : pOut->SetRasterOp( nROP2 );
196 : }
197 0 : break;
198 :
199 : case W_META_SETTEXTCOLOR:
200 : {
201 0 : pOut->SetTextColor( ReadColor() );
202 : }
203 0 : break;
204 :
205 : case W_META_SETWINDOWORG:
206 : {
207 0 : pOut->SetWinOrg( ReadYX() );
208 : }
209 0 : break;
210 :
211 : case W_META_SETWINDOWEXT:
212 : {
213 0 : short nWidth = 0, nHeight = 0;
214 0 : pWMF->ReadInt16( nHeight ).ReadInt16( nWidth );
215 0 : pOut->SetWinExt( Size( nWidth, nHeight ) );
216 : }
217 0 : break;
218 :
219 : case W_META_OFFSETWINDOWORG:
220 : {
221 0 : short nXAdd = 0, nYAdd = 0;
222 0 : pWMF->ReadInt16( nYAdd ).ReadInt16( nXAdd );
223 0 : pOut->SetWinOrgOffset( nXAdd, nYAdd );
224 : }
225 0 : break;
226 :
227 : case W_META_SCALEWINDOWEXT:
228 : {
229 0 : short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0;
230 0 : pWMF->ReadInt16( nYDenom ).ReadInt16( nYNum ).ReadInt16( nXDenom ).ReadInt16( nXNum );
231 0 : pOut->ScaleWinExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom );
232 : }
233 0 : break;
234 :
235 : case W_META_SETVIEWPORTORG:
236 : case W_META_SETVIEWPORTEXT:
237 0 : break;
238 :
239 : case W_META_OFFSETVIEWPORTORG:
240 : {
241 0 : short nXAdd = 0, nYAdd = 0;
242 0 : pWMF->ReadInt16( nYAdd ).ReadInt16( nXAdd );
243 0 : pOut->SetDevOrgOffset( nXAdd, nYAdd );
244 : }
245 0 : break;
246 :
247 : case W_META_SCALEVIEWPORTEXT:
248 : {
249 0 : short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0;
250 0 : pWMF->ReadInt16( nYDenom ).ReadInt16( nYNum ).ReadInt16( nXDenom ).ReadInt16( nXNum );
251 0 : pOut->ScaleDevExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom );
252 : }
253 0 : break;
254 :
255 : case W_META_LINETO:
256 : {
257 0 : pOut->LineTo( ReadYX() );
258 : }
259 0 : break;
260 :
261 : case W_META_MOVETO:
262 : {
263 0 : pOut->MoveTo( ReadYX() );
264 : }
265 0 : break;
266 :
267 : case W_META_INTERSECTCLIPRECT:
268 : {
269 0 : pOut->IntersectClipRect( ReadRectangle() );
270 : }
271 0 : break;
272 :
273 : case W_META_RECTANGLE:
274 : {
275 0 : pOut->DrawRect( ReadRectangle() );
276 : }
277 0 : break;
278 :
279 : case W_META_ROUNDRECT:
280 : {
281 0 : Size aSize( ReadYXExt() );
282 0 : pOut->DrawRoundRect( ReadRectangle(), Size( aSize.Width() / 2, aSize.Height() / 2 ) );
283 : }
284 0 : break;
285 :
286 : case W_META_ELLIPSE:
287 : {
288 0 : pOut->DrawEllipse( ReadRectangle() );
289 : }
290 0 : break;
291 :
292 : case W_META_ARC:
293 : {
294 0 : Point aEnd( ReadYX() );
295 0 : Point aStart( ReadYX() );
296 0 : Rectangle aRect( ReadRectangle() );
297 0 : aRect.Justify();
298 0 : pOut->DrawArc( aRect, aStart, aEnd );
299 : }
300 0 : break;
301 :
302 : case W_META_PIE:
303 : {
304 0 : Point aEnd( ReadYX() );
305 0 : Point aStart( ReadYX() );
306 0 : Rectangle aRect( ReadRectangle() );
307 0 : aRect.Justify();
308 :
309 : // #i73608# OutputDevice deviates from WMF
310 : // semantics. start==end means full ellipse here.
311 0 : if( aStart == aEnd )
312 0 : pOut->DrawEllipse( aRect );
313 : else
314 0 : pOut->DrawPie( aRect, aStart, aEnd );
315 : }
316 0 : break;
317 :
318 : case W_META_CHORD:
319 : {
320 0 : Point aEnd( ReadYX() );
321 0 : Point aStart( ReadYX() );
322 0 : Rectangle aRect( ReadRectangle() );
323 0 : aRect.Justify();
324 0 : pOut->DrawChord( aRect, aStart, aEnd );
325 : }
326 0 : break;
327 :
328 : case W_META_POLYGON:
329 : {
330 0 : sal_uInt16 nPoints = 0;
331 0 : pWMF->ReadUInt16( nPoints );
332 0 : Polygon aPoly( nPoints );
333 0 : for( sal_uInt16 i = 0; i < nPoints; i++ )
334 0 : aPoly[ i ] = ReadPoint();
335 0 : pOut->DrawPolygon( aPoly );
336 : }
337 0 : break;
338 :
339 : case W_META_POLYPOLYGON:
340 : {
341 0 : bool bRecordOk = true;
342 0 : sal_uInt16 nPolyCount(0);
343 : // Number of polygons:
344 0 : pWMF->ReadUInt16( nPolyCount );
345 0 : if (nPolyCount && pWMF->good())
346 : {
347 : // Number of points of each polygon. Determine total number of points
348 0 : boost::scoped_array<sal_uInt16> xPolygonPointCounts(new sal_uInt16[nPolyCount]);
349 0 : sal_uInt16* pnPoints = xPolygonPointCounts.get();
350 0 : PolyPolygon aPolyPoly(nPolyCount, nPolyCount);
351 0 : sal_uInt16 nPoints = 0;
352 0 : for (sal_uInt16 a = 0; a < nPolyCount && pWMF->good(); ++a)
353 : {
354 0 : pWMF->ReadUInt16( pnPoints[a] );
355 :
356 0 : if (pnPoints[a] > SAL_MAX_UINT16 - nPoints)
357 : {
358 0 : bRecordOk = false;
359 0 : break;
360 : }
361 :
362 0 : nPoints += pnPoints[a];
363 : }
364 :
365 : SAL_WARN_IF(!bRecordOk, "vcl.filter", "polypolygon record has more polygons than we can handle");
366 :
367 0 : bRecordOk &= pWMF->good();
368 :
369 0 : if (!bRecordOk)
370 : {
371 0 : pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
372 0 : break;
373 : }
374 :
375 : // Polygon points are:
376 0 : for (sal_uInt16 a = 0; a < nPolyCount && pWMF->good(); ++a)
377 : {
378 0 : const sal_uInt16 nPointCount(pnPoints[a]);
379 0 : boost::scoped_array<Point> xPolygonPoints(new Point[nPointCount]);
380 0 : Point* pPtAry = xPolygonPoints.get();
381 :
382 0 : for(sal_uInt16 b(0); b < nPointCount && pWMF->good(); ++b)
383 : {
384 0 : pPtAry[b] = ReadPoint();
385 : }
386 :
387 0 : aPolyPoly.Insert(Polygon(nPointCount, pPtAry));
388 0 : }
389 :
390 0 : bRecordOk &= pWMF->good();
391 :
392 0 : if (!bRecordOk)
393 : {
394 0 : pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
395 0 : break;
396 : }
397 :
398 0 : pOut->DrawPolyPolygon( aPolyPoly );
399 : }
400 : }
401 0 : break;
402 :
403 : case W_META_POLYLINE:
404 : {
405 0 : sal_uInt16 nPoints = 0;
406 0 : pWMF->ReadUInt16( nPoints );
407 0 : Polygon aPoly( nPoints );
408 0 : for(sal_uInt16 i = 0; i < nPoints; i++ )
409 0 : aPoly[ i ] = ReadPoint();
410 0 : pOut->DrawPolyLine( aPoly );
411 : }
412 0 : break;
413 :
414 : case W_META_SAVEDC:
415 : {
416 0 : pOut->Push();
417 : }
418 0 : break;
419 :
420 : case W_META_RESTOREDC:
421 : {
422 0 : pOut->Pop();
423 : }
424 0 : break;
425 :
426 : case W_META_SETPIXEL:
427 : {
428 0 : const Color aColor = ReadColor();
429 0 : pOut->DrawPixel( ReadYX(), aColor );
430 : }
431 0 : break;
432 :
433 : case W_META_OFFSETCLIPRGN:
434 : {
435 0 : pOut->MoveClipRegion( ReadYXExt() );
436 : }
437 0 : break;
438 :
439 : case W_META_TEXTOUT:
440 : {
441 0 : sal_uInt16 nLength = 0;
442 0 : pWMF->ReadUInt16( nLength );
443 0 : if ( nLength )
444 : {
445 0 : boost::scoped_array<char> pChar(new char[ ( nLength + 1 ) &~ 1 ]);
446 0 : pWMF->Read( pChar.get(), ( nLength + 1 ) &~ 1 );
447 0 : OUString aText( pChar.get(), nLength, pOut->GetCharSet() );
448 0 : pChar.reset();
449 0 : Point aPosition( ReadYX() );
450 0 : pOut->DrawText( aPosition, aText );
451 : }
452 : }
453 0 : break;
454 :
455 : case W_META_EXTTEXTOUT:
456 : {
457 0 : sal_uInt16 nLen = 0, nOptions = 0;
458 0 : sal_Int32 nRecordPos, nRecordSize = 0, nOriginalTextLen, nNewTextLen;
459 0 : Point aPosition;
460 0 : Rectangle aRect;
461 0 : boost::scoped_array<sal_Int32> pDXAry;
462 :
463 0 : pWMF->SeekRel(-6);
464 0 : nRecordPos = pWMF->Tell();
465 0 : pWMF->ReadInt32( nRecordSize );
466 0 : pWMF->SeekRel(2);
467 0 : aPosition = ReadYX();
468 0 : pWMF->ReadUInt16( nLen ).ReadUInt16( nOptions );
469 :
470 0 : sal_Int32 nTextLayoutMode = TEXT_LAYOUT_DEFAULT;
471 0 : if ( nOptions & ETO_RTLREADING )
472 0 : nTextLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT;
473 0 : pOut->SetTextLayoutMode( nTextLayoutMode );
474 : DBG_ASSERT( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) == 0, "SJ: ETO_PDY || ETO_GLYPH_INDEX in WMF" );
475 :
476 : // output only makes sense if the text contains characters
477 0 : if( nLen )
478 : {
479 0 : nOriginalTextLen = nLen;
480 0 : if( nOptions & ETO_CLIPPED )
481 : {
482 0 : const Point aPt1( ReadPoint() );
483 0 : const Point aPt2( ReadPoint() );
484 0 : aRect = Rectangle( aPt1, aPt2 );
485 : }
486 0 : boost::scoped_array<char> pChar(new char[ ( nOriginalTextLen + 1 ) &~ 1 ]);
487 0 : pWMF->Read( pChar.get(), ( nOriginalTextLen + 1 ) &~ 1 );
488 0 : OUString aText( pChar.get(), (sal_uInt16)nOriginalTextLen, pOut->GetCharSet() );// after this conversion the text may contain
489 0 : nNewTextLen = aText.getLength(); // less character (japanese version), so the
490 0 : pChar.reset(); // dxAry will not fit
491 :
492 0 : if ( nNewTextLen )
493 : {
494 0 : sal_uInt32 nMaxStreamPos = nRecordPos + ( nRecordSize << 1 );
495 0 : sal_Int32 nDxArySize = nMaxStreamPos - pWMF->Tell();
496 0 : sal_Int32 nDxAryEntries = nDxArySize >> 1;
497 0 : bool bUseDXAry = false;
498 :
499 0 : if ( ( ( nDxAryEntries % nOriginalTextLen ) == 0 ) && ( nNewTextLen <= nOriginalTextLen ) )
500 : {
501 0 : sal_Int16 nDx = 0, nDxTmp = 0;
502 : sal_uInt16 i; //needed just outside the for
503 0 : pDXAry.reset(new sal_Int32[ nNewTextLen ]);
504 0 : for (i = 0; i < nNewTextLen; i++ )
505 : {
506 0 : if ( pWMF->Tell() >= nMaxStreamPos )
507 0 : break;
508 0 : pWMF->ReadInt16( nDx );
509 0 : if ( nNewTextLen != nOriginalTextLen )
510 : {
511 0 : sal_Unicode nUniChar = aText[i];
512 0 : OString aTmp(&nUniChar, 1, pOut->GetCharSet());
513 0 : if ( aTmp.getLength() > 1 )
514 : {
515 0 : sal_Int32 nDxCount = aTmp.getLength() - 1;
516 0 : if ( ( ( nDxCount * 2 ) + pWMF->Tell() ) > nMaxStreamPos )
517 0 : break;
518 0 : while ( nDxCount-- )
519 : {
520 0 : pWMF->ReadInt16( nDxTmp );
521 0 : nDx = nDx + nDxTmp;
522 : }
523 0 : }
524 : }
525 0 : pDXAry[ i ] = nDx;
526 : }
527 0 : if ( i == nNewTextLen )
528 0 : bUseDXAry = true;
529 : }
530 0 : if ( pDXAry && bUseDXAry )
531 0 : pOut->DrawText( aPosition, aText, pDXAry.get() );
532 : else
533 0 : pOut->DrawText( aPosition, aText );
534 0 : }
535 0 : }
536 : }
537 0 : break;
538 :
539 : case W_META_SELECTOBJECT:
540 : {
541 0 : sal_Int16 nObjIndex = 0;
542 0 : pWMF->ReadInt16( nObjIndex );
543 0 : pOut->SelectObject( nObjIndex );
544 : }
545 0 : break;
546 :
547 : case W_META_SETTEXTALIGN:
548 : {
549 0 : sal_uInt16 nAlign = 0;
550 0 : pWMF->ReadUInt16( nAlign );
551 0 : pOut->SetTextAlign( nAlign );
552 : }
553 0 : break;
554 :
555 : case W_META_BITBLT:
556 : {
557 : // 0-3 : nWinROP #93454#
558 : // 4-5 : y offset of source bitmap
559 : // 6-7 : x offset of source bitmap
560 : // 8-9 : used height of source bitmap
561 : // 10-11 : used width of source bitmap
562 : // 12-13 : destination position y (in pixel)
563 : // 14-15 : destination position x (in pixel)
564 : // 16-17 : dont know
565 : // 18-19 : Width Bitmap in Pixel
566 : // 20-21 : Height Bitmap in Pixel
567 : // 22-23 : bytes per scanline
568 : // 24 : planes
569 : // 25 : bitcount
570 :
571 0 : sal_Int32 nWinROP = 0;
572 0 : sal_uInt16 nSx = 0, nSy = 0, nSxe = 0, nSye = 0, nDontKnow = 0, nWidth = 0, nHeight = 0, nBytesPerScan = 0;
573 : sal_uInt8 nPlanes, nBitCount;
574 :
575 0 : pWMF->ReadInt32( nWinROP )
576 0 : .ReadUInt16( nSy ).ReadUInt16( nSx ).ReadUInt16( nSye ).ReadUInt16( nSxe );
577 0 : Point aPoint( ReadYX() );
578 0 : pWMF->ReadUInt16( nDontKnow ).ReadUInt16( nWidth ).ReadUInt16( nHeight ).ReadUInt16( nBytesPerScan ).ReadUChar( nPlanes ).ReadUChar( nBitCount );
579 :
580 0 : if ( nWidth && nHeight && ( nPlanes == 1 ) && ( nBitCount == 1 ) )
581 : {
582 0 : Bitmap aBmp( Size( nWidth, nHeight ), nBitCount );
583 : BitmapWriteAccess* pAcc;
584 0 : pAcc = aBmp.AcquireWriteAccess();
585 0 : if ( pAcc )
586 : {
587 0 : for (sal_uInt16 y = 0; y < nHeight; y++ )
588 : {
589 0 : sal_uInt16 x = 0;
590 0 : for (sal_uInt16 scan = 0; scan < nBytesPerScan; scan++ )
591 : {
592 0 : sal_Int8 nEightPixels = 0;
593 0 : pWMF->ReadSChar( nEightPixels );
594 0 : for (sal_Int8 i = 7; i >= 0; i-- )
595 : {
596 0 : if ( x < nWidth )
597 : {
598 0 : pAcc->SetPixelIndex( y, x, (nEightPixels>>i)&1 );
599 : }
600 0 : x++;
601 : }
602 : }
603 : }
604 0 : aBmp.ReleaseAccess( pAcc );
605 0 : if ( nSye && nSxe &&
606 0 : ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) &&
607 0 : ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) )
608 : {
609 0 : Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) );
610 0 : aBmp.Crop( aCropRect );
611 : }
612 0 : Rectangle aDestRect( aPoint, Size( nSxe, nSye ) );
613 0 : aBmpSaveList.push_back( new BSaveStruct( aBmp, aDestRect, nWinROP, pOut->GetFillStyle () ) );
614 0 : }
615 : }
616 : }
617 0 : break;
618 :
619 : case W_META_STRETCHBLT:
620 : case W_META_DIBBITBLT:
621 : case W_META_DIBSTRETCHBLT:
622 : case W_META_STRETCHDIB:
623 : {
624 0 : sal_Int32 nWinROP = 0;
625 0 : sal_uInt16 nSx = 0, nSy = 0, nSxe = 0, nSye = 0, nUsage = 0;
626 0 : Bitmap aBmp;
627 :
628 0 : pWMF->ReadInt32( nWinROP );
629 :
630 0 : if( nFunc == W_META_STRETCHDIB )
631 0 : pWMF->ReadUInt16( nUsage );
632 :
633 : // nSye and nSxe is the number of pixels that has to been used
634 : // If they are set to zero, it is as indicator not to scale the bitmap later
635 :
636 0 : if( nFunc == W_META_STRETCHDIB || nFunc == W_META_STRETCHBLT || nFunc == W_META_DIBSTRETCHBLT )
637 0 : pWMF->ReadUInt16( nSye ).ReadUInt16( nSxe );
638 :
639 : // nSy and nx is the offset of the first pixel
640 0 : pWMF->ReadUInt16( nSy ).ReadUInt16( nSx );
641 :
642 0 : if( nFunc == W_META_STRETCHDIB || nFunc == W_META_DIBBITBLT || nFunc == W_META_DIBSTRETCHBLT )
643 : {
644 0 : if ( nWinROP == PATCOPY )
645 0 : pWMF->ReadUInt16( nUsage ); // i don't know anything of this parameter, so its called nUsage
646 : // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), false );
647 :
648 0 : Size aDestSize( ReadYXExt() );
649 0 : if ( aDestSize.Width() && aDestSize.Height() ) // #92623# do not try to read buggy bitmaps
650 : {
651 0 : Rectangle aDestRect( ReadYX(), aDestSize );
652 0 : if ( nWinROP != PATCOPY )
653 0 : ReadDIB(aBmp, *pWMF, false);
654 :
655 : // test if it is sensible to crop
656 0 : if ( nSye && nSxe &&
657 0 : ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) &&
658 0 : ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) )
659 : {
660 0 : Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) );
661 0 : aBmp.Crop( aCropRect );
662 : }
663 0 : aBmpSaveList.push_back( new BSaveStruct( aBmp, aDestRect, nWinROP, pOut->GetFillStyle () ) );
664 : }
665 0 : }
666 : }
667 0 : break;
668 :
669 : case W_META_DIBCREATEPATTERNBRUSH:
670 : {
671 0 : Bitmap aBmp;
672 : BitmapReadAccess* pBmp;
673 0 : sal_uInt32 nRed = 0, nGreen = 0, nBlue = 0, nCount = 1;
674 0 : sal_uInt16 nFunction = 0;
675 :
676 0 : pWMF->ReadUInt16( nFunction ).ReadUInt16( nFunction );
677 :
678 0 : ReadDIB(aBmp, *pWMF, false);
679 0 : pBmp = aBmp.AcquireReadAccess();
680 0 : if ( pBmp )
681 : {
682 0 : for ( sal_Int32 y = 0; y < pBmp->Height(); y++ )
683 : {
684 0 : for ( sal_Int32 x = 0; x < pBmp->Width(); x++ )
685 : {
686 0 : const BitmapColor aColor( pBmp->GetColor( y, x ) );
687 :
688 0 : nRed += aColor.GetRed();
689 0 : nGreen += aColor.GetGreen();
690 0 : nBlue += aColor.GetBlue();
691 0 : }
692 : }
693 0 : nCount = pBmp->Height() * pBmp->Width();
694 0 : if ( !nCount )
695 0 : nCount++;
696 0 : aBmp.ReleaseAccess( pBmp );
697 : }
698 0 : Color aColor( (sal_uInt8)( nRed / nCount ), (sal_uInt8)( nGreen / nCount ), (sal_uInt8)( nBlue / nCount ) );
699 0 : pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( aColor, false ) );
700 : }
701 0 : break;
702 :
703 : case W_META_DELETEOBJECT:
704 : {
705 0 : sal_Int16 nIndex = 0;
706 0 : pWMF->ReadInt16( nIndex );
707 0 : pOut->DeleteObject( nIndex );
708 : }
709 0 : break;
710 :
711 : case W_META_CREATEPALETTE:
712 : {
713 0 : pOut->CreateObject( GDI_DUMMY );
714 : }
715 0 : break;
716 :
717 : case W_META_CREATEBRUSH:
718 : {
719 0 : pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ), false ) );
720 : }
721 0 : break;
722 :
723 : case W_META_CREATEPATTERNBRUSH:
724 : {
725 0 : pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ), false ) );
726 : }
727 0 : break;
728 :
729 : case W_META_CREATEPENINDIRECT:
730 : {
731 0 : LineInfo aLineInfo;
732 0 : sal_uInt16 nStyle = 0, nWidth = 0, nHeight = 0;
733 :
734 0 : pWMF->ReadUInt16( nStyle ).ReadUInt16( nWidth ).ReadUInt16( nHeight );
735 :
736 0 : if ( nWidth )
737 0 : aLineInfo.SetWidth( nWidth );
738 :
739 0 : bool bTransparent = false;
740 0 : switch( nStyle & 0xFF )
741 : {
742 : case PS_DASHDOTDOT :
743 0 : aLineInfo.SetStyle( LINE_DASH );
744 0 : aLineInfo.SetDashCount( 1 );
745 0 : aLineInfo.SetDotCount( 2 );
746 0 : aLineInfo.SetDashLen( 150 );
747 0 : aLineInfo.SetDotLen( 30 );
748 0 : aLineInfo.SetDistance( 50 );
749 0 : break;
750 : case PS_DASHDOT :
751 0 : aLineInfo.SetStyle( LINE_DASH );
752 0 : aLineInfo.SetDashCount( 1 );
753 0 : aLineInfo.SetDotCount( 1 );
754 0 : aLineInfo.SetDashLen( 150 );
755 0 : aLineInfo.SetDotLen( 30 );
756 0 : aLineInfo.SetDistance( 90 );
757 0 : break;
758 : case PS_DOT :
759 0 : aLineInfo.SetStyle( LINE_DASH );
760 0 : aLineInfo.SetDashCount( 0 );
761 0 : aLineInfo.SetDotCount( 1 );
762 0 : aLineInfo.SetDotLen( 30 );
763 0 : aLineInfo.SetDistance( 50 );
764 0 : break;
765 : case PS_DASH :
766 0 : aLineInfo.SetStyle( LINE_DASH );
767 0 : aLineInfo.SetDashCount( 1 );
768 0 : aLineInfo.SetDotCount( 0 );
769 0 : aLineInfo.SetDashLen( 225 );
770 0 : aLineInfo.SetDistance( 100 );
771 0 : break;
772 : case PS_NULL :
773 0 : bTransparent = true;
774 0 : aLineInfo.SetStyle( LINE_NONE );
775 0 : break;
776 : default :
777 : case PS_INSIDEFRAME :
778 : case PS_SOLID :
779 0 : aLineInfo.SetStyle( LINE_SOLID );
780 : }
781 0 : switch( nStyle & 0xF00 )
782 : {
783 : case PS_ENDCAP_ROUND :
784 0 : aLineInfo.SetLineCap( com::sun::star::drawing::LineCap_ROUND );
785 0 : break;
786 : case PS_ENDCAP_SQUARE :
787 0 : aLineInfo.SetLineCap( com::sun::star::drawing::LineCap_SQUARE );
788 0 : break;
789 : case PS_ENDCAP_FLAT :
790 : default :
791 0 : aLineInfo.SetLineCap( com::sun::star::drawing::LineCap_BUTT );
792 : }
793 0 : switch( nStyle & 0xF000 )
794 : {
795 : case PS_JOIN_ROUND :
796 0 : aLineInfo.SetLineJoin ( basegfx::B2DLINEJOIN_ROUND );
797 0 : break;
798 : case PS_JOIN_MITER :
799 0 : aLineInfo.SetLineJoin ( basegfx::B2DLINEJOIN_MITER );
800 0 : break;
801 : case PS_JOIN_BEVEL :
802 0 : aLineInfo.SetLineJoin ( basegfx::B2DLINEJOIN_BEVEL );
803 0 : break;
804 : default :
805 0 : aLineInfo.SetLineJoin ( basegfx::B2DLINEJOIN_NONE );
806 : }
807 0 : pOut->CreateObject( GDI_PEN, new WinMtfLineStyle( ReadColor(), aLineInfo, bTransparent ) );
808 : }
809 0 : break;
810 :
811 : case W_META_CREATEBRUSHINDIRECT:
812 : {
813 0 : sal_uInt16 nStyle = 0;
814 0 : pWMF->ReadUInt16( nStyle );
815 0 : pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( ReadColor(), ( nStyle == BS_HOLLOW ) ? true : false ) );
816 : }
817 0 : break;
818 :
819 : case W_META_CREATEFONTINDIRECT:
820 : {
821 0 : Size aFontSize;
822 : char lfFaceName[ LF_FACESIZE ];
823 0 : sal_Int16 lfEscapement = 0, lfOrientation = 0, lfWeight = 0; // ( formerly sal_uInt16 )
824 :
825 0 : LOGFONTW aLogFont;
826 0 : aFontSize = ReadYXExt();
827 0 : pWMF->ReadInt16( lfEscapement ).ReadInt16( lfOrientation ).ReadInt16( lfWeight )
828 0 : .ReadUChar( aLogFont.lfItalic ).ReadUChar( aLogFont.lfUnderline ).ReadUChar( aLogFont.lfStrikeOut ).ReadUChar( aLogFont.lfCharSet ).ReadUChar( aLogFont.lfOutPrecision )
829 0 : .ReadUChar( aLogFont.lfClipPrecision ).ReadUChar( aLogFont.lfQuality ).ReadUChar( aLogFont.lfPitchAndFamily );
830 0 : pWMF->Read( lfFaceName, LF_FACESIZE );
831 0 : aLogFont.lfWidth = aFontSize.Width();
832 0 : aLogFont.lfHeight = aFontSize.Height();
833 0 : aLogFont.lfEscapement = lfEscapement;
834 0 : aLogFont.lfOrientation = lfOrientation;
835 0 : aLogFont.lfWeight = lfWeight;
836 :
837 : rtl_TextEncoding eCharSet;
838 0 : if ( ( aLogFont.lfCharSet == OEM_CHARSET ) || ( aLogFont.lfCharSet == DEFAULT_CHARSET ) )
839 0 : eCharSet = osl_getThreadTextEncoding();
840 : else
841 0 : eCharSet = rtl_getTextEncodingFromWindowsCharset( aLogFont.lfCharSet );
842 0 : if ( eCharSet == RTL_TEXTENCODING_DONTKNOW )
843 0 : eCharSet = osl_getThreadTextEncoding();
844 0 : if ( eCharSet == RTL_TEXTENCODING_SYMBOL )
845 0 : eCharSet = RTL_TEXTENCODING_MS_1252;
846 0 : aLogFont.alfFaceName = OUString( lfFaceName, strlen(lfFaceName), eCharSet );
847 :
848 0 : pOut->CreateObject( GDI_FONT, new WinMtfFontStyle( aLogFont ) );
849 : }
850 0 : break;
851 :
852 : case W_META_CREATEBITMAPINDIRECT:
853 : {
854 0 : pOut->CreateObject( GDI_DUMMY );
855 : }
856 0 : break;
857 :
858 : case W_META_CREATEBITMAP:
859 : {
860 0 : pOut->CreateObject( GDI_DUMMY );
861 : }
862 0 : break;
863 :
864 : case W_META_CREATEREGION:
865 : {
866 0 : pOut->CreateObject( GDI_DUMMY );
867 : }
868 0 : break;
869 :
870 : case W_META_EXCLUDECLIPRECT :
871 : {
872 0 : pOut->ExcludeClipRect( ReadRectangle() );
873 : }
874 0 : break;
875 :
876 : case W_META_PATBLT:
877 : {
878 0 : sal_uInt32 nROP = 0, nOldROP = 0;
879 0 : pWMF->ReadUInt32( nROP );
880 0 : Size aSize = ReadYXExt();
881 0 : nOldROP = pOut->SetRasterOp( nROP );
882 0 : pOut->DrawRect( Rectangle( ReadYX(), aSize ), false );
883 0 : pOut->SetRasterOp( nOldROP );
884 : }
885 0 : break;
886 :
887 : case W_META_SELECTCLIPREGION:
888 : {
889 0 : sal_Int16 nObjIndex = 0;
890 0 : pWMF->ReadInt16( nObjIndex );
891 0 : if ( !nObjIndex )
892 : {
893 0 : PolyPolygon aEmptyPolyPoly;
894 0 : pOut->SetClipPath( aEmptyPolyPoly, RGN_COPY, true );
895 : }
896 : }
897 0 : break;
898 :
899 : case W_META_ESCAPE :
900 : {
901 : // nRecSize has been checked previously to be greater than 3
902 0 : sal_uInt64 nMetaRecSize = static_cast< sal_uInt64 >( nRecSize - 2 ) * 2;
903 0 : sal_uInt64 nMetaRecEndPos = pWMF->Tell() + nMetaRecSize;
904 :
905 : // taking care that nRecSize does not exceed the maximal stream position
906 0 : if ( nMetaRecEndPos > nEndPos )
907 : {
908 0 : pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
909 0 : break;
910 : }
911 0 : if ( nRecSize >= 4 ) // minimal escape length
912 : {
913 0 : sal_uInt16 nMode = 0, nLen = 0;
914 0 : pWMF->ReadUInt16( nMode )
915 0 : .ReadUInt16( nLen );
916 0 : if ( ( nMode == W_MFCOMMENT ) && ( nLen >= 4 ) )
917 : {
918 0 : sal_uInt32 nNewMagic = 0; // we have to read int32 for
919 0 : pWMF->ReadUInt32( nNewMagic ); // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier
920 :
921 0 : if( nNewMagic == 0x2c2a4f4f && nLen >= 14 )
922 : {
923 0 : sal_uInt16 nMagic2 = 0;
924 0 : pWMF->ReadUInt16( nMagic2 );
925 0 : if( nMagic2 == 0x0a ) // 2nd half of magic
926 : { // continue with private escape
927 0 : sal_uInt32 nCheck = 0, nEsc = 0;
928 0 : pWMF->ReadUInt32( nCheck )
929 0 : .ReadUInt32( nEsc );
930 :
931 0 : sal_uInt32 nEscLen = nLen - 14;
932 0 : if ( nEscLen <= ( nRecSize * 2 ) )
933 : {
934 : #ifdef OSL_BIGENDIAN
935 : sal_uInt32 nTmp = OSL_SWAPDWORD( nEsc );
936 : sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 );
937 : #else
938 0 : sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 );
939 : #endif
940 0 : boost::scoped_array<sal_Int8> pData;
941 :
942 0 : if ( ( static_cast< sal_uInt64 >( nEscLen ) + pWMF->Tell() ) > nMetaRecEndPos )
943 : {
944 0 : pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
945 0 : break;
946 : }
947 0 : if ( nEscLen > 0 )
948 : {
949 0 : pData.reset(new sal_Int8[ nEscLen ]);
950 0 : pWMF->Read( pData.get(), nEscLen );
951 0 : nCheckSum = rtl_crc32( nCheckSum, pData.get(), nEscLen );
952 : }
953 0 : if ( nCheck == nCheckSum )
954 : {
955 0 : switch( nEsc )
956 : {
957 : case PRIVATE_ESCAPE_UNICODE :
958 : {
959 : // we will use text instead of polygons only if we have the correct font
960 0 : if ( Application::GetDefaultDevice()->IsFontAvailable( pOut->GetFont().GetName() ) )
961 : {
962 0 : Point aPt;
963 0 : OUString aString;
964 : sal_uInt32 nStringLen, nDXCount;
965 0 : boost::scoped_array<sal_Int32> pDXAry;
966 0 : SvMemoryStream aMemoryStream( nEscLen );
967 0 : aMemoryStream.Write( pData.get(), nEscLen );
968 0 : aMemoryStream.Seek( STREAM_SEEK_TO_BEGIN );
969 : //#fdo39428 SvStream no longer supports operator>>(long&)
970 0 : sal_Int32 nTmpX(0), nTmpY(0);
971 0 : aMemoryStream.ReadInt32( nTmpX )
972 0 : .ReadInt32( nTmpY )
973 0 : .ReadUInt32( nStringLen );
974 0 : aPt.X() = nTmpX;
975 0 : aPt.Y() = nTmpY;
976 :
977 0 : if ( ( static_cast< sal_uInt64 >( nStringLen ) * sizeof( sal_Unicode ) ) < ( nEscLen - aMemoryStream.Tell() ) )
978 : {
979 :
980 0 : aString = read_uInt16s_ToOUString(aMemoryStream, nStringLen);
981 0 : aMemoryStream.ReadUInt32( nDXCount );
982 0 : if ( ( static_cast< sal_uInt64 >( nDXCount ) * sizeof( sal_Int32 ) ) >= ( nEscLen - aMemoryStream.Tell() ) )
983 0 : nDXCount = 0;
984 0 : if ( nDXCount )
985 0 : pDXAry.reset(new sal_Int32[ nDXCount ]);
986 0 : for (sal_uInt32 i = 0; i < nDXCount; i++ )
987 0 : aMemoryStream.ReadInt32( pDXAry[ i ] );
988 0 : aMemoryStream.ReadUInt32( nSkipActions );
989 0 : pOut->DrawText( aPt, aString, pDXAry.get() );
990 0 : }
991 : }
992 : }
993 0 : break;
994 : }
995 0 : }
996 : }
997 0 : }
998 : }
999 0 : else if ( (nNewMagic == static_cast< sal_uInt32 >(0x43464D57)) && (nLen >= 34) && ( (sal_Int32)(nLen + 10) <= (sal_Int32)(nRecSize * 2) ))
1000 : {
1001 0 : sal_uInt32 nComType = 0, nVersion = 0, nFlags = 0, nComRecCount = 0,
1002 0 : nCurRecSize = 0, nRemainingSize = 0, nEMFTotalSize = 0;
1003 0 : sal_uInt16 nCheck = 0;
1004 :
1005 0 : pWMF->ReadUInt32( nComType ).ReadUInt32( nVersion ).ReadUInt16( nCheck ).ReadUInt32( nFlags )
1006 0 : .ReadUInt32( nComRecCount ).ReadUInt32( nCurRecSize )
1007 0 : .ReadUInt32( nRemainingSize ).ReadUInt32( nEMFTotalSize ); // the nRemainingSize is not mentioned in MSDN documentation
1008 : // but it seems to be required to read in data produced by OLE
1009 :
1010 0 : if( nComType == 0x01 && nVersion == 0x10000 && nComRecCount )
1011 : {
1012 0 : if( !nEMFRec )
1013 : { // first EMF comment
1014 0 : nEMFRecCount = nComRecCount;
1015 0 : nEMFSize = nEMFTotalSize;
1016 0 : pEMFStream = new SvMemoryStream( nEMFSize );
1017 : }
1018 0 : else if( ( nEMFRecCount != nComRecCount ) || ( nEMFSize != nEMFTotalSize ) ) // add additional checks here
1019 : {
1020 : // total records should be the same as in previous comments
1021 0 : nEMFRecCount = 0xFFFFFFFF;
1022 0 : delete pEMFStream;
1023 0 : pEMFStream = NULL;
1024 : }
1025 0 : nEMFRec++;
1026 :
1027 0 : if( pEMFStream && nCurRecSize + 34 > nLen )
1028 : {
1029 0 : nEMFRecCount = 0xFFFFFFFF;
1030 0 : delete pEMFStream;
1031 0 : pEMFStream = NULL;
1032 : }
1033 :
1034 0 : if( pEMFStream )
1035 : {
1036 0 : boost::scoped_array<sal_Int8> pBuf(new sal_Int8[ nCurRecSize ]);
1037 0 : sal_uInt32 nCount = pWMF->Read( pBuf.get(), nCurRecSize );
1038 0 : if( nCount == nCurRecSize )
1039 0 : pEMFStream->Write( pBuf.get(), nCount );
1040 : }
1041 : }
1042 : }
1043 : }
1044 : }
1045 : }
1046 0 : break;
1047 :
1048 : case W_META_SETRELABS:
1049 : case W_META_SETPOLYFILLMODE:
1050 : case W_META_SETSTRETCHBLTMODE:
1051 : case W_META_SETTEXTCHAREXTRA:
1052 : case W_META_SETTEXTJUSTIFICATION:
1053 : case W_META_FLOODFILL :
1054 : case W_META_FILLREGION:
1055 : case W_META_FRAMEREGION:
1056 : case W_META_INVERTREGION:
1057 : case W_META_PAINTREGION:
1058 : case W_META_DRAWTEXT:
1059 : case W_META_SETMAPPERFLAGS:
1060 : case W_META_SETDIBTODEV:
1061 : case W_META_SELECTPALETTE:
1062 : case W_META_REALIZEPALETTE:
1063 : case W_META_ANIMATEPALETTE:
1064 : case W_META_SETPALENTRIES:
1065 : case W_META_RESIZEPALETTE:
1066 : case W_META_EXTFLOODFILL:
1067 : case W_META_RESETDC:
1068 : case W_META_STARTDOC:
1069 : case W_META_STARTPAGE:
1070 : case W_META_ENDPAGE:
1071 : case W_META_ABORTDOC:
1072 : case W_META_ENDDOC:
1073 0 : break;
1074 : }
1075 0 : }
1076 :
1077 0 : bool WMFReader::ReadHeader()
1078 : {
1079 0 : sal_Size nStrmPos = pWMF->Tell();
1080 :
1081 0 : sal_uInt32 nPlaceableMetaKey(0);
1082 : // if available read the METAFILEHEADER
1083 0 : pWMF->ReadUInt32( nPlaceableMetaKey );
1084 0 : if (!pWMF->good())
1085 0 : return false;
1086 :
1087 0 : Rectangle aPlaceableBound;
1088 :
1089 0 : if (nPlaceableMetaKey == 0x9ac6cdd7L)
1090 : { //TODO do some real error handling here
1091 : sal_Int16 nVal;
1092 :
1093 : // Skip reserved bytes
1094 0 : pWMF->SeekRel(2);
1095 :
1096 : // BoundRect
1097 0 : pWMF->ReadInt16( nVal );
1098 0 : aPlaceableBound.Left() = nVal;
1099 0 : pWMF->ReadInt16( nVal );
1100 0 : aPlaceableBound.Top() = nVal;
1101 0 : pWMF->ReadInt16( nVal );
1102 0 : aPlaceableBound.Right() = nVal;
1103 0 : pWMF->ReadInt16( nVal );
1104 0 : aPlaceableBound.Bottom() = nVal;
1105 :
1106 : // inch
1107 0 : pWMF->ReadUInt16( nUnitsPerInch );
1108 :
1109 : // reserved
1110 0 : pWMF->SeekRel( 4 );
1111 :
1112 : // Skip and don't check the checksum
1113 0 : pWMF->SeekRel( 2 );
1114 : }
1115 : else
1116 : {
1117 0 : nUnitsPerInch = 96;
1118 0 : pWMF->Seek( nStrmPos + 18 ); // set the streampos to the start of the metaactions
1119 0 : GetPlaceableBound( aPlaceableBound, pWMF );
1120 0 : pWMF->Seek( nStrmPos );
1121 0 : if ( pExternalHeader != NULL && ( pExternalHeader->mapMode == MM_ISOTROPIC
1122 0 : || pExternalHeader->mapMode == MM_ANISOTROPIC ) )
1123 : {
1124 : // #n417818#: If we have an external header then overwrite the bounds!
1125 : Rectangle aExtRect(0, 0,
1126 0 : pExternalHeader->xExt*567*nUnitsPerInch/1440/1000,
1127 0 : pExternalHeader->yExt*567*nUnitsPerInch/1440/1000);
1128 0 : GetWinExtMax( aExtRect, aPlaceableBound, pExternalHeader->mapMode );
1129 0 : pOut->SetMapMode( pExternalHeader->mapMode );
1130 : }
1131 : }
1132 :
1133 0 : pOut->SetWinOrg( aPlaceableBound.TopLeft() );
1134 0 : Size aWMFSize( labs( aPlaceableBound.GetWidth() ), labs( aPlaceableBound.GetHeight() ) );
1135 0 : pOut->SetWinExt( aWMFSize );
1136 :
1137 0 : Size aDevExt( 10000, 10000 );
1138 0 : if( ( labs( aWMFSize.Width() ) > 1 ) && ( labs( aWMFSize.Height() ) > 1 ) )
1139 : {
1140 0 : const Fraction aFrac( 1, nUnitsPerInch );
1141 0 : MapMode aWMFMap( MAP_INCH, Point(), aFrac, aFrac );
1142 0 : Size aSize100( OutputDevice::LogicToLogic( aWMFSize, aWMFMap, MAP_100TH_MM ) );
1143 0 : aDevExt = Size( labs( aSize100.Width() ), labs( aSize100.Height() ) );
1144 : }
1145 0 : pOut->SetDevExt( aDevExt );
1146 :
1147 : // read the METAHEADER
1148 0 : sal_uInt32 nMetaKey(0);
1149 0 : pWMF->ReadUInt32( nMetaKey ); // type and headersize
1150 0 : if (!pWMF->good())
1151 0 : return false;
1152 0 : if (nMetaKey != 0x00090001)
1153 : {
1154 0 : sal_uInt16 aNextWord(0);
1155 0 : pWMF->ReadUInt16( aNextWord );
1156 0 : if (nMetaKey != 0x10000 || aNextWord != 0x09)
1157 : {
1158 0 : pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
1159 0 : return false;
1160 : }
1161 : }
1162 :
1163 0 : pWMF->SeekRel( 2 ); // Version (of Windows)
1164 0 : pWMF->SeekRel( 4 ); // Size (of file in words)
1165 0 : pWMF->SeekRel( 2 ); // NoObjects (maximum number of simultaneous objects)
1166 0 : pWMF->SeekRel( 4 ); // MaxRecord (size of largets record in words)
1167 0 : pWMF->SeekRel( 2 ); // NoParameters (Unused
1168 :
1169 0 : return pWMF->good();
1170 : }
1171 :
1172 0 : void WMFReader::ReadWMF()
1173 : {
1174 : sal_uInt16 nFunction;
1175 : sal_uLong nPos, nPercent, nLastPercent;
1176 :
1177 0 : nSkipActions = 0;
1178 0 : nCurrentAction = 0;
1179 0 : nUnicodeEscapeAction = 0;
1180 :
1181 0 : pEMFStream = NULL;
1182 0 : nEMFRecCount = 0;
1183 0 : nEMFRec = 0;
1184 0 : nEMFSize = 0;
1185 :
1186 0 : bool bEMFAvailable = false;
1187 :
1188 0 : pOut->SetMapMode( MM_ANISOTROPIC );
1189 0 : pOut->SetWinOrg( Point() );
1190 0 : pOut->SetWinExt( Size( 1, 1 ) );
1191 0 : pOut->SetDevExt( Size( 10000, 10000 ) );
1192 :
1193 0 : nEndPos=pWMF->Seek( STREAM_SEEK_TO_END );
1194 0 : pWMF->Seek( nStartPos );
1195 0 : Callback( (sal_uInt16) ( nLastPercent = 0 ) );
1196 :
1197 0 : if ( ReadHeader( ) )
1198 : {
1199 :
1200 0 : nPos = pWMF->Tell();
1201 :
1202 0 : if( nEndPos - nStartPos )
1203 : {
1204 : while( true )
1205 : {
1206 0 : nCurrentAction++;
1207 0 : nPercent = ( nPos - nStartPos ) * 100 / ( nEndPos - nStartPos );
1208 :
1209 0 : if( nLastPercent + 4 <= nPercent )
1210 : {
1211 0 : Callback( (sal_uInt16) nPercent );
1212 0 : nLastPercent = nPercent;
1213 : }
1214 0 : pWMF->ReadUInt32( nRecSize ).ReadUInt16( nFunction );
1215 :
1216 0 : if( pWMF->GetError()
1217 0 : || ( nRecSize < 3 )
1218 0 : || ( nRecSize == 3
1219 0 : && nFunction == 0
1220 : )
1221 0 : || pWMF->IsEof()
1222 : )
1223 : {
1224 0 : if( pWMF->IsEof() )
1225 0 : pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
1226 :
1227 0 : break;
1228 : }
1229 0 : if ( !bEMFAvailable )
1230 : {
1231 0 : if( !aBmpSaveList.empty()
1232 0 : && ( nFunction != W_META_STRETCHDIB )
1233 0 : && ( nFunction != W_META_DIBBITBLT )
1234 0 : && ( nFunction != W_META_DIBSTRETCHBLT )
1235 : )
1236 : {
1237 0 : pOut->ResolveBitmapActions( aBmpSaveList );
1238 : }
1239 :
1240 0 : if ( !nSkipActions )
1241 0 : ReadRecordParams( nFunction );
1242 : else
1243 0 : nSkipActions--;
1244 :
1245 0 : if( pEMFStream && nEMFRecCount == nEMFRec )
1246 : {
1247 0 : GDIMetaFile aMeta;
1248 0 : pEMFStream->Seek( 0 );
1249 0 : EnhWMFReader* pEMFReader = new EnhWMFReader ( *pEMFStream, aMeta );
1250 0 : bEMFAvailable = pEMFReader->ReadEnhWMF();
1251 0 : delete pEMFReader; // destroy first!!!
1252 :
1253 0 : if( bEMFAvailable )
1254 : {
1255 0 : pOut->AddFromGDIMetaFile( aMeta );
1256 0 : pOut->SetrclFrame( Rectangle( Point(0, 0), aMeta.GetPrefSize()));
1257 :
1258 : // the stream needs to be set to the wmf end position,
1259 : // otherwise the GfxLink that is created will be incorrect
1260 : // (leading to graphic loss after swapout/swapin).
1261 : // so we will proceed normally, but are ignoring further wmf
1262 : // records
1263 : }
1264 : else
1265 : {
1266 : // something went wrong
1267 : // continue with WMF, don't try this again
1268 0 : delete pEMFStream;
1269 0 : pEMFStream = NULL;
1270 0 : }
1271 : }
1272 : }
1273 0 : nPos += nRecSize * 2;
1274 0 : if ( nPos <= nEndPos )
1275 0 : pWMF->Seek( nPos );
1276 : else
1277 0 : pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
1278 0 : }
1279 : }
1280 : else
1281 0 : pWMF->SetError( SVSTREAM_GENERALERROR );
1282 :
1283 0 : if( !pWMF->GetError() && !aBmpSaveList.empty() )
1284 0 : pOut->ResolveBitmapActions( aBmpSaveList );
1285 : }
1286 0 : if ( pWMF->GetError() )
1287 0 : pWMF->Seek( nStartPos );
1288 0 : }
1289 :
1290 0 : bool WMFReader::GetPlaceableBound( Rectangle& rPlaceableBound, SvStream* pStm )
1291 : {
1292 0 : bool bRet = true;
1293 :
1294 0 : rPlaceableBound.Left() = (sal_Int32)0x7fffffff;
1295 0 : rPlaceableBound.Top() = (sal_Int32)0x7fffffff;
1296 0 : rPlaceableBound.Right() = (sal_Int32)0x80000000;
1297 0 : rPlaceableBound.Bottom() = (sal_Int32)0x80000000;
1298 :
1299 0 : sal_uInt32 nPos = pStm->Tell();
1300 0 : sal_uInt32 nEnd = pStm->Seek( STREAM_SEEK_TO_END );
1301 :
1302 0 : pStm->Seek( nPos );
1303 :
1304 0 : if( nEnd - nPos )
1305 : {
1306 0 : sal_Int16 nMapMode = MM_ANISOTROPIC;
1307 : sal_uInt16 nFunction;
1308 : sal_uInt32 nRSize;
1309 :
1310 0 : while( bRet )
1311 : {
1312 0 : pStm->ReadUInt32( nRSize ).ReadUInt16( nFunction );
1313 :
1314 0 : if( pStm->GetError() || ( nRSize < 3 ) || ( nRSize==3 && nFunction==0 ) || pStm->IsEof() )
1315 : {
1316 0 : if( pStm->IsEof() )
1317 : {
1318 0 : pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1319 0 : bRet = false;
1320 : }
1321 0 : break;
1322 : }
1323 0 : switch( nFunction )
1324 : {
1325 : case W_META_SETWINDOWORG:
1326 : {
1327 0 : Point aWinOrg;
1328 0 : aWinOrg = ReadYX();
1329 0 : rPlaceableBound.SetPos( aWinOrg );
1330 : }
1331 0 : break;
1332 :
1333 : case W_META_SETWINDOWEXT:
1334 : {
1335 0 : sal_Int16 nWidth(0), nHeight(0);
1336 0 : pStm->ReadInt16( nHeight ).ReadInt16( nWidth );
1337 0 : rPlaceableBound.SetSize( Size( nWidth, nHeight ) );
1338 : }
1339 0 : break;
1340 :
1341 : case W_META_SETMAPMODE :
1342 0 : pStm->ReadInt16( nMapMode );
1343 0 : break;
1344 :
1345 : case W_META_MOVETO:
1346 : case W_META_LINETO:
1347 0 : GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode );
1348 0 : break;
1349 :
1350 : case W_META_RECTANGLE:
1351 : case W_META_INTERSECTCLIPRECT:
1352 : case W_META_EXCLUDECLIPRECT :
1353 : case W_META_ELLIPSE:
1354 0 : GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode );
1355 0 : break;
1356 :
1357 : case W_META_ROUNDRECT:
1358 0 : ReadYXExt(); // size
1359 0 : GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode );
1360 0 : break;
1361 :
1362 : case W_META_ARC:
1363 : case W_META_PIE:
1364 : case W_META_CHORD:
1365 0 : ReadYX(); // end
1366 0 : ReadYX(); // start
1367 0 : GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode );
1368 0 : break;
1369 :
1370 : case W_META_POLYGON:
1371 : {
1372 : sal_uInt16 nPoints;
1373 0 : pStm->ReadUInt16( nPoints );
1374 0 : for(sal_uInt16 i = 0; i < nPoints; i++ )
1375 0 : GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode );
1376 : }
1377 0 : break;
1378 :
1379 : case W_META_POLYPOLYGON:
1380 : {
1381 0 : bool bRecordOk = true;
1382 0 : sal_uInt16 nPoly, nPoints = 0;
1383 0 : pStm->ReadUInt16( nPoly );
1384 0 : for(sal_uInt16 i = 0; i < nPoly; i++ )
1385 : {
1386 0 : sal_uInt16 nP = 0;
1387 0 : pStm->ReadUInt16( nP );
1388 0 : if (nP > SAL_MAX_UINT16 - nPoints)
1389 : {
1390 0 : bRecordOk = false;
1391 0 : break;
1392 : }
1393 0 : nPoints += nP;
1394 : }
1395 :
1396 : SAL_WARN_IF(!bRecordOk, "vcl.filter", "polypolygon record has more polygons than we can handle");
1397 :
1398 0 : bRecordOk &= pStm->good();
1399 :
1400 0 : if (!bRecordOk)
1401 : {
1402 0 : pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1403 0 : bRet = false;
1404 0 : break;
1405 : }
1406 :
1407 0 : for (sal_uInt16 i = 0; i < nPoints; i++ )
1408 0 : GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode );
1409 :
1410 0 : bRecordOk &= pStm->good();
1411 :
1412 0 : if (!bRecordOk)
1413 : {
1414 0 : pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1415 0 : bRet = false;
1416 0 : break;
1417 : }
1418 : }
1419 0 : break;
1420 :
1421 : case W_META_POLYLINE:
1422 : {
1423 : sal_uInt16 nPoints;
1424 0 : pStm->ReadUInt16( nPoints );
1425 0 : for(sal_uInt16 i = 0; i < nPoints; i++ )
1426 0 : GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode );
1427 : }
1428 0 : break;
1429 :
1430 : case W_META_SETPIXEL:
1431 : {
1432 0 : ReadColor();
1433 0 : GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode );
1434 : }
1435 0 : break;
1436 :
1437 : case W_META_TEXTOUT:
1438 : {
1439 : sal_uInt16 nLength;
1440 0 : pStm->ReadUInt16( nLength );
1441 : // todo: we also have to take care of the text width
1442 0 : if ( nLength )
1443 : {
1444 0 : pStm->SeekRel( ( nLength + 1 ) &~ 1 );
1445 0 : GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode );
1446 : }
1447 : }
1448 0 : break;
1449 :
1450 : case W_META_EXTTEXTOUT:
1451 : {
1452 : sal_uInt16 nLen, nOptions;
1453 0 : Point aPosition;
1454 :
1455 0 : aPosition = ReadYX();
1456 0 : pStm->ReadUInt16( nLen ).ReadUInt16( nOptions );
1457 : // todo: we also have to take care of the text width
1458 0 : if( nLen )
1459 0 : GetWinExtMax( aPosition, rPlaceableBound, nMapMode );
1460 : }
1461 0 : break;
1462 : case W_META_BITBLT:
1463 : case W_META_STRETCHBLT:
1464 : case W_META_DIBBITBLT:
1465 : case W_META_DIBSTRETCHBLT:
1466 : case W_META_STRETCHDIB:
1467 : {
1468 : sal_Int32 nWinROP;
1469 : sal_uInt16 nSx, nSy, nSxe, nSye, nUsage;
1470 0 : pStm->ReadInt32( nWinROP );
1471 :
1472 0 : if( nFunction == W_META_STRETCHDIB )
1473 0 : pStm->ReadUInt16( nUsage );
1474 :
1475 : // nSye and nSxe is the number of pixels that has to been used
1476 0 : if( nFunction == W_META_STRETCHDIB || nFunction == W_META_STRETCHBLT || nFunction == W_META_DIBSTRETCHBLT )
1477 0 : pStm->ReadUInt16( nSye ).ReadUInt16( nSxe );
1478 : else
1479 0 : nSye = nSxe = 0; // set this to zero as indicator not to scale the bitmap later
1480 :
1481 : // nSy and nx is the offset of the first pixel
1482 0 : pStm->ReadUInt16( nSy ).ReadUInt16( nSx );
1483 :
1484 0 : if( nFunction == W_META_STRETCHDIB || nFunction == W_META_DIBBITBLT || nFunction == W_META_DIBSTRETCHBLT )
1485 : {
1486 0 : if ( nWinROP == PATCOPY )
1487 0 : pStm->ReadUInt16( nUsage ); // i don't know anything of this parameter, so its called nUsage
1488 : // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), false );
1489 :
1490 0 : Size aDestSize( ReadYXExt() );
1491 0 : if ( aDestSize.Width() && aDestSize.Height() ) // #92623# do not try to read buggy bitmaps
1492 : {
1493 0 : Rectangle aDestRect( ReadYX(), aDestSize );
1494 0 : GetWinExtMax( aDestRect, rPlaceableBound, nMapMode );
1495 : }
1496 : }
1497 : }
1498 0 : break;
1499 :
1500 : case W_META_PATBLT:
1501 : {
1502 : sal_uInt32 nROP;
1503 0 : pStm->ReadUInt32( nROP );
1504 0 : Size aSize = ReadYXExt();
1505 0 : GetWinExtMax( Rectangle( ReadYX(), aSize ), rPlaceableBound, nMapMode );
1506 : }
1507 0 : break;
1508 : }
1509 0 : nPos += nRSize * 2;
1510 0 : if ( nPos <= nEnd )
1511 0 : pStm->Seek( nPos );
1512 : else
1513 : {
1514 0 : pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
1515 0 : bRet = false;
1516 : }
1517 :
1518 : }
1519 : }
1520 : else
1521 : {
1522 0 : pStm->SetError( SVSTREAM_GENERALERROR );
1523 0 : bRet = false;
1524 : }
1525 0 : return bRet;
1526 : }
1527 :
1528 0 : WMFReader::~WMFReader()
1529 : {
1530 0 : if( pEMFStream )
1531 0 : delete pEMFStream;
1532 0 : }
1533 :
1534 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|