1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <o3tl/safeint.hxx>
21 #include <osl/endian.h>
22 #include <filter/importcgm.hxx>
23 #include <tools/stream.hxx>
26 #include "elements.hxx"
29 #include <sal/log.hxx>
30 #include <comphelper/diagnose_ex.hxx>
32 using namespace ::com::sun::star
;
34 constexpr double gnOutdx
= 28000; // Output size in 1/100TH mm
35 constexpr double gnOutdy
= 21000; // on which is mapped
37 CGM::CGM(uno::Reference
< frame::XModel
> const & rModel
)
51 , mbPictureBody(false)
53 , mbFirstOutPut(false)
54 , mbInDefaultReplacement(false)
57 , mpOutAct(new CGMImpressOutAct(*this, rModel
))
59 , mpEndValidSource(nullptr)
67 pElement
.reset( new CGMElements
);
68 pCopyOfE
.reset( new CGMElements
);
74 maDefRepSizeList
.clear();
77 sal_uInt32
CGM::GetBackGroundColor() const
79 return pElement
? pElement
->aColorTable
[ 0 ] : 0;
82 sal_uInt32
CGM::ImplGetUI16()
84 sal_uInt8
* pSource
= mpSource
+ mnParaSize
;
85 if (mpEndValidSource
- pSource
< 2)
86 throw css::uno::Exception(u
"attempt to read past end of input"_ustr
, nullptr);
88 return ( pSource
[ 0 ] << 8 ) + pSource
[ 1 ];
91 sal_uInt8
CGM::ImplGetByte( sal_uInt32 nSource
, sal_uInt32 nPrecision
)
93 return static_cast<sal_uInt8
>( nSource
>> ( ( nPrecision
- 1 ) << 3 ) );
96 sal_Int32
CGM::ImplGetI( sal_uInt32 nPrecision
)
98 sal_uInt8
* pSource
= mpSource
+ mnParaSize
;
99 if (pSource
> mpEndValidSource
|| o3tl::make_unsigned(mpEndValidSource
- pSource
) < nPrecision
)
100 throw css::uno::Exception(u
"attempt to read past end of input"_ustr
, nullptr);
101 mnParaSize
+= nPrecision
;
106 return static_cast<char>(*pSource
);
111 return static_cast<sal_Int16
>( ( pSource
[ 0 ] << 8 ) | pSource
[ 1 ] );
116 return ( ( pSource
[ 0 ] << 24 ) | ( pSource
[ 1 ] << 16 ) | pSource
[ 2 ] << 8 ) >> 8;
120 return static_cast<sal_Int32
>( ( pSource
[ 0 ] << 24 ) | ( pSource
[ 1 ] << 16 ) | ( pSource
[ 2 ] << 8 ) | ( pSource
[ 3 ] ) );
128 sal_uInt32
CGM::ImplGetUI( sal_uInt32 nPrecision
)
130 sal_uInt8
* pSource
= mpSource
+ mnParaSize
;
131 if (pSource
> mpEndValidSource
|| o3tl::make_unsigned(mpEndValidSource
- pSource
) < nPrecision
)
132 throw css::uno::Exception(u
"attempt to read past end of input"_ustr
, nullptr);
133 mnParaSize
+= nPrecision
;
137 return static_cast<sal_Int8
>(*pSource
);
140 return static_cast<sal_uInt16
>( ( pSource
[ 0 ] << 8 ) | pSource
[ 1 ] );
144 return ( pSource
[ 0 ] << 16 ) | ( pSource
[ 1 ] << 8 ) | pSource
[ 2 ];
148 return static_cast<sal_uInt32
>( ( pSource
[ 0 ] << 24 ) | ( pSource
[ 1 ] << 16 ) | ( pSource
[ 2 ] << 8 ) | ( pSource
[ 3 ] ) );
156 void CGM::ImplGetSwitch4( const sal_uInt8
* pSource
, sal_uInt8
* pDest
)
158 for ( int i
= 0; i
< 4; i
++ )
160 pDest
[ i
] = pSource
[ i
^ 3 ]; // Little Endian <-> Big Endian switch
164 void CGM::ImplGetSwitch8( const sal_uInt8
* pSource
, sal_uInt8
* pDest
)
166 for ( int i
= 0; i
< 8; i
++ )
168 pDest
[ i
] = pSource
[ i
^ 7 ]; // Little Endian <-> Big Endian switch
172 double CGM::ImplGetFloat( RealPrecision eRealPrecision
, sal_uInt32 nRealSize
)
181 const bool bCompatible
= true;
183 const bool bCompatible
= false;
186 if (o3tl::make_unsigned(mpEndValidSource
- (mpSource
+ mnParaSize
)) < nRealSize
)
187 throw css::uno::Exception(u
"attempt to read past end of input"_ustr
, nullptr);
191 pPtr
= mpSource
+ mnParaSize
;
195 if ( nRealSize
== 4 )
196 ImplGetSwitch4( mpSource
+ mnParaSize
, &aBuf
[0] );
198 ImplGetSwitch8( mpSource
+ mnParaSize
, &aBuf
[0] );
201 if ( eRealPrecision
== RP_FLOAT
)
203 if ( nRealSize
== 4 )
205 memcpy( static_cast<void*>(&fFloatBuf
), pPtr
, 4 );
206 nRetValue
= static_cast<double>(fFloatBuf
);
210 memcpy( static_cast<void*>(&fDoubleBuf
), pPtr
, 8 );
211 nRetValue
= fDoubleBuf
;
217 const int nSwitch
= bCompatible
? 0 : 1 ;
218 if ( nRealSize
== 4 )
220 sal_uInt16
* pShort
= static_cast<sal_uInt16
*>(pPtr
);
221 nVal
= pShort
[ nSwitch
];
223 nVal
|= pShort
[ nSwitch
^ 1 ];
224 nRetValue
= static_cast<double>(nVal
);
229 sal_Int32
* pLong
= static_cast<sal_Int32
*>(pPtr
);
230 nRetValue
= fabs(static_cast<double>(pLong
[nSwitch
]));
232 nVal
= static_cast<sal_uInt32
>( pLong
[ nSwitch
^ 1 ] );
234 nRetValue
+= static_cast<double>(nVal
);
235 if ( pLong
[ nSwitch
] < 0 )
237 nRetValue
= -nRetValue
;
242 mnParaSize
+= nRealSize
;
246 sal_uInt32
CGM::ImplGetPointSize()
248 if ( pElement
->eVDCType
== VDC_INTEGER
)
249 return pElement
->nVDCIntegerPrecision
<< 1;
251 return pElement
->nVDCRealSize
<< 1;
254 inline double CGM::ImplGetIX()
256 return ( ( ImplGetI( pElement
->nVDCIntegerPrecision
) + mnVDCXadd
) * mnVDCXmul
);
259 inline double CGM::ImplGetFX()
261 return ( ( ImplGetFloat( pElement
->eVDCRealPrecision
, pElement
->nVDCRealSize
) + mnVDCXadd
) * mnVDCXmul
);
264 inline double CGM::ImplGetIY()
266 return ( ( ImplGetI( pElement
->nVDCIntegerPrecision
) + mnVDCYadd
) * mnVDCYmul
);
269 inline double CGM::ImplGetFY()
271 return ( ( ImplGetFloat( pElement
->eVDCRealPrecision
, pElement
->nVDCRealSize
) + mnVDCYadd
) * mnVDCYmul
);
274 void CGM::ImplGetPoint( FloatPoint
& rFloatPoint
, bool bMap
)
276 if ( pElement
->eVDCType
== VDC_INTEGER
)
278 rFloatPoint
.X
= ImplGetIX();
279 rFloatPoint
.Y
= ImplGetIY();
281 else // ->floating points
283 rFloatPoint
.X
= ImplGetFX();
284 rFloatPoint
.Y
= ImplGetFY();
287 ImplMapPoint( rFloatPoint
);
290 void CGM::ImplGetRectangle( FloatRect
& rFloatRect
, bool bMap
)
292 if ( pElement
->eVDCType
== VDC_INTEGER
)
294 rFloatRect
.Left
= ImplGetIX();
295 rFloatRect
.Bottom
= ImplGetIY();
296 rFloatRect
.Right
= ImplGetIX();
297 rFloatRect
.Top
= ImplGetIY();
299 else // ->floating points
301 rFloatRect
.Left
= ImplGetFX();
302 rFloatRect
.Bottom
= ImplGetFY();
303 rFloatRect
.Right
= ImplGetFX();
304 rFloatRect
.Top
= ImplGetFY();
308 ImplMapX( rFloatRect
.Left
);
309 ImplMapX( rFloatRect
.Right
);
310 ImplMapY( rFloatRect
.Top
);
311 ImplMapY( rFloatRect
.Bottom
);
312 rFloatRect
.Justify();
316 void CGM::ImplGetRectangleNS( FloatRect
& rFloatRect
)
318 if ( pElement
->eVDCType
== VDC_INTEGER
)
320 rFloatRect
.Left
= ImplGetI( pElement
->nVDCIntegerPrecision
);
321 rFloatRect
.Bottom
= ImplGetI( pElement
->nVDCIntegerPrecision
);
322 rFloatRect
.Right
= ImplGetI( pElement
->nVDCIntegerPrecision
);
323 rFloatRect
.Top
= ImplGetI( pElement
->nVDCIntegerPrecision
);
325 else // ->floating points
327 rFloatRect
.Left
= ImplGetFloat( pElement
->eVDCRealPrecision
, pElement
->nVDCRealSize
);
328 rFloatRect
.Bottom
= ImplGetFloat( pElement
->eVDCRealPrecision
, pElement
->nVDCRealSize
);
329 rFloatRect
.Right
= ImplGetFloat( pElement
->eVDCRealPrecision
, pElement
->nVDCRealSize
);
330 rFloatRect
.Top
= ImplGetFloat( pElement
->eVDCRealPrecision
, pElement
->nVDCRealSize
);
334 sal_uInt32
CGM::ImplGetBitmapColor( bool bDirect
)
336 // the background color is always a direct color
339 if ( ( pElement
->eColorSelectionMode
== CSM_DIRECT
) || bDirect
)
341 sal_uInt32 nColor
= ImplGetByte( ImplGetUI( pElement
->nColorPrecision
), 1 );
342 sal_uInt32 nDiff
= pElement
->nColorValueExtent
[ 3 ] - pElement
->nColorValueExtent
[ 0 ] + 1;
346 nColor
= ( ( nColor
- pElement
->nColorValueExtent
[ 0 ] ) << 8 ) / nDiff
;
347 nTmp
= nColor
<< 16 & 0xff0000;
349 nColor
= ImplGetByte( ImplGetUI( pElement
->nColorPrecision
), 1 );
350 nDiff
= pElement
->nColorValueExtent
[ 4 ] - pElement
->nColorValueExtent
[ 1 ] + 1;
353 nColor
= ( ( nColor
- pElement
->nColorValueExtent
[ 1 ] ) << 8 ) / nDiff
;
354 nTmp
|= nColor
<< 8 & 0xff00;
356 nColor
= ImplGetByte( ImplGetUI( pElement
->nColorPrecision
), 1 );
357 nDiff
= pElement
->nColorValueExtent
[ 5 ] - pElement
->nColorValueExtent
[ 2 ] + 1;
360 nColor
= ( ( nColor
- pElement
->nColorValueExtent
[ 2 ] ) << 8 ) / nDiff
;
361 nTmp
|= static_cast<sal_uInt8
>(nColor
);
365 sal_uInt32 nIndex
= ImplGetUI( pElement
->nColorIndexPrecision
);
366 nTmp
= pElement
->aColorTable
[ static_cast<sal_uInt8
>(nIndex
) ] ;
371 // call this function each time after the mapmode settings has been changed
372 void CGM::ImplSetMapMode()
375 mnVDCdx
= pElement
->aVDCExtent
.Right
- pElement
->aVDCExtent
.Left
;
377 mnVDCXadd
= -pElement
->aVDCExtent
.Left
;
386 mnVDCdy
= pElement
->aVDCExtent
.Bottom
- pElement
->aVDCExtent
.Top
;
387 mnVDCYadd
= -pElement
->aVDCExtent
.Top
;
398 mbAngReverse
= false;
400 if (mnVDCdy
== 0.0 || mnVDCdx
== 0.0 || gnOutdy
== 0.0)
406 double fQuo1
= mnVDCdx
/ mnVDCdy
;
407 double fQuo2
= gnOutdx
/ gnOutdy
;
410 mnXFraction
= gnOutdx
/ mnVDCdx
;
411 mnYFraction
= gnOutdy
* ( fQuo2
/ fQuo1
) / mnVDCdy
;
415 mnXFraction
= gnOutdx
* ( fQuo1
/ fQuo2
) / mnVDCdx
;
416 mnYFraction
= gnOutdy
/ mnVDCdy
;
420 void CGM::ImplMapDouble( double& nNumb
)
422 if ( pElement
->eDeviceViewPortMap
!= DVPM_FORCED
)
425 // point is 1mm * ScalingFactor
426 switch ( pElement
->eDeviceViewPortMode
)
430 nNumb
*= ( mnXFraction
+ mnYFraction
) / 2;
436 // nNumb *= ( 100 * pElement->nDeviceViewPortScale );
437 nNumb
*= ( mnXFraction
+ mnYFraction
) / 2;
438 if ( pElement
->nDeviceViewPortScale
< 0 )
455 void CGM::ImplMapX( double& nNumb
)
457 if ( pElement
->eDeviceViewPortMap
!= DVPM_FORCED
)
460 // point is 1mm * ScalingFactor
461 switch ( pElement
->eDeviceViewPortMode
)
465 nNumb
*= mnXFraction
;
471 // nNumb *= ( 100 * pElement->nDeviceViewPortScale );
472 nNumb
*= mnXFraction
;
473 if ( pElement
->nDeviceViewPortScale
< 0 )
490 void CGM::ImplMapY( double& nNumb
)
492 if ( pElement
->eDeviceViewPortMap
!= DVPM_FORCED
)
495 // point is 1mm * ScalingFactor
496 switch ( pElement
->eDeviceViewPortMode
)
500 nNumb
*= mnYFraction
;
506 // nNumb *= ( 100 * pElement->nDeviceViewPortScale );
507 nNumb
*= mnYFraction
;
508 if ( pElement
->nDeviceViewPortScale
< 0 )
525 // convert a point to the current VC mapmode (1/100TH mm)
526 void CGM::ImplMapPoint( FloatPoint
& rFloatPoint
)
528 if ( pElement
->eDeviceViewPortMap
!= DVPM_FORCED
)
531 // point is 1mm * ScalingFactor
532 switch ( pElement
->eDeviceViewPortMode
)
536 rFloatPoint
.X
*= mnXFraction
;
537 rFloatPoint
.Y
*= mnYFraction
;
543 rFloatPoint
.X
*= mnXFraction
;
544 rFloatPoint
.Y
*= mnYFraction
;
545 if ( pElement
->nDeviceViewPortScale
< 0 )
547 rFloatPoint
.X
= -rFloatPoint
.X
;
548 rFloatPoint
.Y
= -rFloatPoint
.Y
;
565 void CGM::ImplDoClass()
567 switch ( mnElementClass
)
569 case 0 : ImplDoClass0(); break;
570 case 1 : ImplDoClass1(); break;
571 case 2 : ImplDoClass2(); break;
572 case 3 : ImplDoClass3(); break;
579 case 5 : ImplDoClass5(); break;
580 case 6 : ImplDoClass6(); break;
581 case 7 : ImplDoClass7(); break;
582 case 8 : ImplDoClass8(); break;
583 case 9 : ImplDoClass9(); break;
584 case 15 :ImplDoClass15(); break;
590 void CGM::ImplDefaultReplacement()
592 if (maDefRepList
.empty())
595 if (mbInDefaultReplacement
)
597 SAL_WARN("filter.icgm", "recursion in ImplDefaultReplacement");
601 mbInDefaultReplacement
= true;
603 sal_uInt32 nOldEscape
= mnEscape
;
604 sal_uInt32 nOldElementClass
= mnElementClass
;
605 sal_uInt32 nOldElementID
= mnElementID
;
606 sal_uInt32 nOldElementSize
= mnElementSize
;
607 sal_uInt8
* pOldBuf
= mpSource
;
608 sal_uInt8
* pOldEndValidSource
= mpEndValidSource
;
610 for ( size_t i
= 0, n
= maDefRepList
.size(); i
< n
; ++i
)
612 sal_uInt8
* pBuf
= maDefRepList
[ i
].get();
613 sal_uInt32 nElementSize
= maDefRepSizeList
[ i
];
614 mpEndValidSource
= pBuf
+ nElementSize
;
615 sal_uInt32 nCount
= 0;
616 while ( mbStatus
&& ( nCount
< nElementSize
) )
618 mpSource
= pBuf
+ nCount
;
620 mnEscape
= ImplGetUI16();
621 mnElementClass
= mnEscape
>> 12;
622 mnElementID
= ( mnEscape
& 0x0fe0 ) >> 5;
623 mnElementSize
= mnEscape
& 0x1f;
624 if ( mnElementSize
== 31 )
626 mnElementSize
= ImplGetUI16();
628 nCount
+= mnParaSize
;
630 mpSource
= pBuf
+ nCount
;
631 if ( mnElementSize
& 1 )
633 nCount
+= mnElementSize
;
634 if ( ( mnElementClass
!= 1 ) || ( mnElementID
!= 0xc ) ) // recursion is not possible here!!
638 mnEscape
= nOldEscape
;
639 mnElementClass
= nOldElementClass
;
640 mnElementID
= nOldElementID
;
641 mnParaSize
= mnElementSize
= nOldElementSize
;
643 mpEndValidSource
= pOldEndValidSource
;
645 mbInDefaultReplacement
= false;
648 bool CGM::Write( SvStream
& rIStm
)
651 mpBuf
.reset( new sal_uInt8
[ 0xffff ] );
654 mpSource
= mpBuf
.get();
655 if (rIStm
.ReadBytes(mpSource
, 2) != 2)
657 mpEndValidSource
= mpSource
+ 2;
658 mnEscape
= ImplGetUI16();
659 mnElementClass
= mnEscape
>> 12;
660 mnElementID
= ( mnEscape
& 0x0fe0 ) >> 5;
661 mnElementSize
= mnEscape
& 0x1f;
663 if ( mnElementSize
== 31 )
665 if (rIStm
.ReadBytes(mpSource
+ mnParaSize
, 2) != 2)
667 mpEndValidSource
= mpSource
+ mnParaSize
+ 2;
668 mnElementSize
= ImplGetUI16();
673 if (rIStm
.ReadBytes(mpSource
, mnElementSize
) != mnElementSize
)
675 mpEndValidSource
= mpSource
+ mnElementSize
;
678 if ( mnElementSize
& 1 )
685 // GraphicImport - the exported function
686 FILTER_DLLPUBLIC sal_uInt32
687 ImportCGM(SvStream
& rIn
, uno::Reference
< frame::XModel
> const & rXModel
, css::uno::Reference
<css::task::XStatusIndicator
> const & aXStatInd
)
690 sal_uInt32 nStatus
= 0; // retvalue == 0 -> ERROR
691 // == 0xffrrggbb -> background color in the lower 24 bits
700 rIn
.SetEndian(SvStreamEndian::BIG
);
701 sal_uInt64
const nInSize
= rIn
.remainingSize();
704 sal_uInt64 nNext
= 0;
705 sal_uInt32 nAdd
= nInSize
/ 20;
706 bool bProgressBar
= aXStatInd
.is();
708 aXStatInd
->start( u
"CGM Import"_ustr
, nInSize
);
710 while (aCGM
.IsValid() && (rIn
.Tell() < nInSize
) && !aCGM
.IsFinished())
714 sal_uInt64 nCurrentPos
= rIn
.Tell();
715 if ( nCurrentPos
>= nNext
)
717 aXStatInd
->setValue( nCurrentPos
);
718 nNext
= nCurrentPos
+ nAdd
;
722 if (!aCGM
.Write(rIn
))
725 if ( aCGM
.IsValid() )
727 nStatus
= aCGM
.GetBackGroundColor() | 0xff000000;
733 catch (const css::uno::Exception
&)
735 TOOLS_WARN_EXCEPTION("filter.icgm", "");
742 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */