Revert "tdf#158280 Replace usage of InputDialog with SvxNameDialog"
[LibreOffice.git] / filter / source / graphicfilter / icgm / cgm.cxx
blobeeeb763ede49ddeedfd8b3c9962699daefd07e9b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
24 #include "bitmap.hxx"
25 #include "chart.hxx"
26 #include "elements.hxx"
27 #include "outact.hxx"
28 #include <memory>
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)
38 : mnVDCXadd(0)
39 , mnVDCYadd(0)
40 , mnVDCXmul(0)
41 , mnVDCYmul(0)
42 , mnVDCdx(0)
43 , mnVDCdy(0)
44 , mnXFraction(0)
45 , mnYFraction(0)
46 , mbAngReverse(false)
47 , mbStatus(true)
48 , mbMetaFile(false)
49 , mbIsFinished(false)
50 , mbPicture(false)
51 , mbPictureBody(false)
52 , mbFigure(false)
53 , mbFirstOutPut(false)
54 , mbInDefaultReplacement(false)
55 , mnAct4PostReset(0)
56 , mnBitmapInserts(0)
57 , mpOutAct(new CGMImpressOutAct(*this, rModel))
58 , mpSource(nullptr)
59 , mpEndValidSource(nullptr)
60 , mnParaSize(0)
61 , mnActCount(0)
62 , mnEscape(0)
63 , mnElementClass(0)
64 , mnElementID(0)
65 , mnElementSize(0)
67 pElement.reset( new CGMElements );
68 pCopyOfE.reset( new CGMElements );
71 CGM::~CGM()
73 maDefRepList.clear();
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);
87 mnParaSize += 2;
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;
102 switch( nPrecision )
104 case 1 :
106 return static_cast<char>(*pSource);
109 case 2 :
111 return static_cast<sal_Int16>( ( pSource[ 0 ] << 8 ) | pSource[ 1 ] );
114 case 3 :
116 return ( ( pSource[ 0 ] << 24 ) | ( pSource[ 1 ] << 16 ) | pSource[ 2 ] << 8 ) >> 8;
118 case 4:
120 return static_cast<sal_Int32>( ( pSource[ 0 ] << 24 ) | ( pSource[ 1 ] << 16 ) | ( pSource[ 2 ] << 8 ) | ( pSource[ 3 ] ) );
122 default:
123 mbStatus = false;
124 return 0;
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;
134 switch( nPrecision )
136 case 1 :
137 return static_cast<sal_Int8>(*pSource);
138 case 2 :
140 return static_cast<sal_uInt16>( ( pSource[ 0 ] << 8 ) | pSource[ 1 ] );
142 case 3 :
144 return ( pSource[ 0 ] << 16 ) | ( pSource[ 1 ] << 8 ) | pSource[ 2 ];
146 case 4:
148 return static_cast<sal_uInt32>( ( pSource[ 0 ] << 24 ) | ( pSource[ 1 ] << 16 ) | ( pSource[ 2 ] << 8 ) | ( pSource[ 3 ] ) );
150 default:
151 mbStatus = false;
152 return 0;
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 )
174 void* pPtr;
175 sal_uInt8 aBuf[8];
176 double nRetValue;
177 double fDoubleBuf;
178 float fFloatBuf;
180 #ifdef OSL_BIGENDIAN
181 const bool bCompatible = true;
182 #else
183 const bool bCompatible = false;
184 #endif
186 if (o3tl::make_unsigned(mpEndValidSource - (mpSource + mnParaSize)) < nRealSize)
187 throw css::uno::Exception(u"attempt to read past end of input"_ustr, nullptr);
189 if ( bCompatible )
191 pPtr = mpSource + mnParaSize;
193 else
195 if ( nRealSize == 4 )
196 ImplGetSwitch4( mpSource + mnParaSize, &aBuf[0] );
197 else
198 ImplGetSwitch8( mpSource + mnParaSize, &aBuf[0] );
199 pPtr = &aBuf;
201 if ( eRealPrecision == RP_FLOAT )
203 if ( nRealSize == 4 )
205 memcpy( static_cast<void*>(&fFloatBuf), pPtr, 4 );
206 nRetValue = static_cast<double>(fFloatBuf);
208 else
210 memcpy( static_cast<void*>(&fDoubleBuf), pPtr, 8 );
211 nRetValue = fDoubleBuf;
214 else // ->RP_FIXED
216 tools::Long nVal;
217 const int nSwitch = bCompatible ? 0 : 1 ;
218 if ( nRealSize == 4 )
220 sal_uInt16* pShort = static_cast<sal_uInt16*>(pPtr);
221 nVal = pShort[ nSwitch ];
222 nVal <<= 16;
223 nVal |= pShort[ nSwitch ^ 1 ];
224 nRetValue = static_cast<double>(nVal);
225 nRetValue /= 65536;
227 else
229 sal_Int32* pLong = static_cast<sal_Int32*>(pPtr);
230 nRetValue = fabs(static_cast<double>(pLong[nSwitch]));
231 nRetValue *= 65536;
232 nVal = static_cast<sal_uInt32>( pLong[ nSwitch ^ 1 ] );
233 nVal >>= 16;
234 nRetValue += static_cast<double>(nVal);
235 if ( pLong[ nSwitch ] < 0 )
237 nRetValue = -nRetValue;
239 nRetValue /= 65536;
242 mnParaSize += nRealSize;
243 return nRetValue;
246 sal_uInt32 CGM::ImplGetPointSize()
248 if ( pElement->eVDCType == VDC_INTEGER )
249 return pElement->nVDCIntegerPrecision << 1;
250 else
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();
286 if ( bMap )
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();
306 if ( bMap )
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
338 sal_uInt32 nTmp;
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;
344 if ( !nDiff )
345 nDiff++;
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;
351 if ( !nDiff )
352 nDiff++;
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;
358 if ( !nDiff )
359 nDiff++;
360 nColor = ( ( nColor - pElement->nColorValueExtent[ 2 ] ) << 8 ) / nDiff;
361 nTmp |= static_cast<sal_uInt8>(nColor);
363 else
365 sal_uInt32 nIndex = ImplGetUI( pElement->nColorIndexPrecision );
366 nTmp = pElement->aColorTable[ static_cast<sal_uInt8>(nIndex) ] ;
368 return nTmp;
371 // call this function each time after the mapmode settings has been changed
372 void CGM::ImplSetMapMode()
374 int nAngReverse = 1;
375 mnVDCdx = pElement->aVDCExtent.Right - pElement->aVDCExtent.Left;
377 mnVDCXadd = -pElement->aVDCExtent.Left;
378 mnVDCXmul = 1;
379 if ( mnVDCdx < 0 )
381 nAngReverse ^= 1;
382 mnVDCdx = -mnVDCdx;
383 mnVDCXmul = -1;
386 mnVDCdy = pElement->aVDCExtent.Bottom - pElement->aVDCExtent.Top;
387 mnVDCYadd = -pElement->aVDCExtent.Top;
388 mnVDCYmul = 1;
389 if ( mnVDCdy < 0 )
391 nAngReverse ^= 1;
392 mnVDCdy = -mnVDCdy;
393 mnVDCYmul = -1;
395 if ( nAngReverse )
396 mbAngReverse = true;
397 else
398 mbAngReverse = false;
400 if (mnVDCdy == 0.0 || mnVDCdx == 0.0 || gnOutdy == 0.0)
402 mbStatus = false;
403 return;
406 double fQuo1 = mnVDCdx / mnVDCdy;
407 double fQuo2 = gnOutdx / gnOutdy;
408 if ( fQuo2 < fQuo1 )
410 mnXFraction = gnOutdx / mnVDCdx;
411 mnYFraction = gnOutdy * ( fQuo2 / fQuo1 ) / mnVDCdy;
413 else
415 mnXFraction = gnOutdx * ( fQuo1 / fQuo2 ) / mnVDCdx;
416 mnYFraction = gnOutdy / mnVDCdy;
420 void CGM::ImplMapDouble( double& nNumb )
422 if ( pElement->eDeviceViewPortMap != DVPM_FORCED )
423 return;
425 // point is 1mm * ScalingFactor
426 switch ( pElement->eDeviceViewPortMode )
428 case DVPM_FRACTION :
430 nNumb *= ( mnXFraction + mnYFraction ) / 2;
432 break;
434 case DVPM_METRIC :
436 // nNumb *= ( 100 * pElement->nDeviceViewPortScale );
437 nNumb *= ( mnXFraction + mnYFraction ) / 2;
438 if ( pElement->nDeviceViewPortScale < 0 )
439 nNumb = -nNumb;
441 break;
443 case DVPM_DEVICE :
447 break;
449 default:
451 break;
455 void CGM::ImplMapX( double& nNumb )
457 if ( pElement->eDeviceViewPortMap != DVPM_FORCED )
458 return;
460 // point is 1mm * ScalingFactor
461 switch ( pElement->eDeviceViewPortMode )
463 case DVPM_FRACTION :
465 nNumb *= mnXFraction;
467 break;
469 case DVPM_METRIC :
471 // nNumb *= ( 100 * pElement->nDeviceViewPortScale );
472 nNumb *= mnXFraction;
473 if ( pElement->nDeviceViewPortScale < 0 )
474 nNumb = -nNumb;
476 break;
478 case DVPM_DEVICE :
482 break;
484 default:
486 break;
490 void CGM::ImplMapY( double& nNumb )
492 if ( pElement->eDeviceViewPortMap != DVPM_FORCED )
493 return;
495 // point is 1mm * ScalingFactor
496 switch ( pElement->eDeviceViewPortMode )
498 case DVPM_FRACTION :
500 nNumb *= mnYFraction;
502 break;
504 case DVPM_METRIC :
506 // nNumb *= ( 100 * pElement->nDeviceViewPortScale );
507 nNumb *= mnYFraction;
508 if ( pElement->nDeviceViewPortScale < 0 )
509 nNumb = -nNumb;
511 break;
513 case DVPM_DEVICE :
517 break;
519 default:
521 break;
525 // convert a point to the current VC mapmode (1/100TH mm)
526 void CGM::ImplMapPoint( FloatPoint& rFloatPoint )
528 if ( pElement->eDeviceViewPortMap != DVPM_FORCED )
529 return;
531 // point is 1mm * ScalingFactor
532 switch ( pElement->eDeviceViewPortMode )
534 case DVPM_FRACTION :
536 rFloatPoint.X *= mnXFraction;
537 rFloatPoint.Y *= mnYFraction;
539 break;
541 case DVPM_METRIC :
543 rFloatPoint.X *= mnXFraction;
544 rFloatPoint.Y *= mnYFraction;
545 if ( pElement->nDeviceViewPortScale < 0 )
547 rFloatPoint.X = -rFloatPoint.X;
548 rFloatPoint.Y = -rFloatPoint.Y;
551 break;
553 case DVPM_DEVICE :
557 break;
559 default:
561 break;
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;
573 case 4 :
575 ImplDoClass4();
576 mnAct4PostReset = 0;
578 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;
585 default: break;
587 mnActCount++;
590 void CGM::ImplDefaultReplacement()
592 if (maDefRepList.empty())
593 return;
595 if (mbInDefaultReplacement)
597 SAL_WARN("filter.icgm", "recursion in ImplDefaultReplacement");
598 return;
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;
619 mnParaSize = 0;
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;
629 mnParaSize = 0;
630 mpSource = pBuf + nCount;
631 if ( mnElementSize & 1 )
632 nCount++;
633 nCount += mnElementSize;
634 if ( ( mnElementClass != 1 ) || ( mnElementID != 0xc ) ) // recursion is not possible here!!
635 ImplDoClass();
638 mnEscape = nOldEscape;
639 mnElementClass = nOldElementClass;
640 mnElementID = nOldElementID;
641 mnParaSize = mnElementSize = nOldElementSize;
642 mpSource = pOldBuf;
643 mpEndValidSource = pOldEndValidSource;
645 mbInDefaultReplacement = false;
648 bool CGM::Write( SvStream& rIStm )
650 if ( !mpBuf )
651 mpBuf.reset( new sal_uInt8[ 0xffff ] );
653 mnParaSize = 0;
654 mpSource = mpBuf.get();
655 if (rIStm.ReadBytes(mpSource, 2) != 2)
656 return false;
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)
666 return false;
667 mpEndValidSource = mpSource + mnParaSize + 2;
668 mnElementSize = ImplGetUI16();
670 mnParaSize = 0;
671 if (mnElementSize)
673 if (rIStm.ReadBytes(mpSource, mnElementSize) != mnElementSize)
674 return false;
675 mpEndValidSource = mpSource + mnElementSize;
678 if ( mnElementSize & 1 )
679 rIStm.SeekRel( 1 );
680 ImplDoClass();
682 return mbStatus;
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
693 if( rXModel.is() )
697 CGM aCGM(rXModel);
698 if (aCGM.IsValid())
700 rIn.SetEndian(SvStreamEndian::BIG);
701 sal_uInt64 const nInSize = rIn.remainingSize();
702 rIn.Seek(0);
704 sal_uInt64 nNext = 0;
705 sal_uInt32 nAdd = nInSize / 20;
706 bool bProgressBar = aXStatInd.is();
707 if ( bProgressBar )
708 aXStatInd->start( u"CGM Import"_ustr , nInSize );
710 while (aCGM.IsValid() && (rIn.Tell() < nInSize) && !aCGM.IsFinished())
712 if ( bProgressBar )
714 sal_uInt64 nCurrentPos = rIn.Tell();
715 if ( nCurrentPos >= nNext )
717 aXStatInd->setValue( nCurrentPos );
718 nNext = nCurrentPos + nAdd;
722 if (!aCGM.Write(rIn))
723 break;
725 if ( aCGM.IsValid() )
727 nStatus = aCGM.GetBackGroundColor() | 0xff000000;
729 if ( bProgressBar )
730 aXStatInd->end();
733 catch (const css::uno::Exception&)
735 TOOLS_WARN_EXCEPTION("filter.icgm", "");
736 nStatus = 0;
739 return nStatus;
742 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */