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