From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- vcl/source/filter/svm/SvmConverter.cxx | 1290 ++++++++++++++++++++++++++++ vcl/source/filter/svm/SvmConverter.hxx | 92 ++ vcl/source/filter/svm/SvmReader.cxx | 1438 ++++++++++++++++++++++++++++++++ vcl/source/filter/svm/SvmWriter.cxx | 1421 +++++++++++++++++++++++++++++++ 4 files changed, 4241 insertions(+) create mode 100644 vcl/source/filter/svm/SvmConverter.cxx create mode 100644 vcl/source/filter/svm/SvmConverter.hxx create mode 100644 vcl/source/filter/svm/SvmReader.cxx create mode 100644 vcl/source/filter/svm/SvmWriter.cxx (limited to 'vcl/source/filter/svm') diff --git a/vcl/source/filter/svm/SvmConverter.cxx b/vcl/source/filter/svm/SvmConverter.cxx new file mode 100644 index 000000000..2e7ed8f35 --- /dev/null +++ b/vcl/source/filter/svm/SvmConverter.cxx @@ -0,0 +1,1290 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "SvmConverter.hxx" + +#include +#include +#include +#include +#include + +// Inlines +static void ImplReadRect( SvStream& rIStm, tools::Rectangle& rRect ) +{ + Point aTL; + Point aBR; + + TypeSerializer aSerializer(rIStm); + aSerializer.readPoint(aTL); + aSerializer.readPoint(aBR); + + rRect = tools::Rectangle( aTL, aBR ); +} + +static bool ImplReadPoly(SvStream& rIStm, tools::Polygon& rPoly) +{ + TypeSerializer aSerializer(rIStm); + + sal_Int32 nSize32(0); + rIStm.ReadInt32(nSize32); + sal_uInt16 nSize = nSize32; + + const size_t nMaxPossiblePoints = rIStm.remainingSize() / 2 * sizeof(sal_Int32); + if (nSize > nMaxPossiblePoints) + { + SAL_WARN("vcl.gdi", "svm record claims to have: " << nSize << " points, but only " << nMaxPossiblePoints << " possible"); + return false; + } + + rPoly = tools::Polygon(nSize); + + for (sal_uInt16 i = 0; i < nSize && rIStm.good(); ++i) + { + aSerializer.readPoint(rPoly[i]); + } + return rIStm.good(); +} + +static bool ImplReadPolyPoly(SvStream& rIStm, tools::PolyPolygon& rPolyPoly) +{ + bool bSuccess = true; + + tools::Polygon aPoly; + sal_Int32 nPolyCount32(0); + rIStm.ReadInt32(nPolyCount32); + sal_uInt16 nPolyCount = static_cast(nPolyCount32); + + for (sal_uInt16 i = 0; i < nPolyCount && rIStm.good(); ++i) + { + if (!ImplReadPoly(rIStm, aPoly)) + { + bSuccess = false; + break; + } + rPolyPoly.Insert(aPoly); + } + + return bSuccess && rIStm.good(); +} + +static void ImplReadColor( SvStream& rIStm, Color& rColor ) +{ + sal_Int16 nVal(0); + + rIStm.ReadInt16( nVal ); rColor.SetRed( sal::static_int_cast(static_cast(nVal) >> 8) ); + rIStm.ReadInt16( nVal ); rColor.SetGreen( sal::static_int_cast(static_cast(nVal) >> 8) ); + rIStm.ReadInt16( nVal ); rColor.SetBlue( sal::static_int_cast(static_cast(nVal) >> 8) ); +} + +static bool ImplReadMapMode(SvStream& rIStm, MapMode& rMapMode) +{ + sal_Int16 nUnit(0); + rIStm.ReadInt16(nUnit); + + Point aOrg; + TypeSerializer aSerializer(rIStm); + aSerializer.readPoint(aOrg); + + sal_Int32 nXNum(0), nXDenom(0), nYNum(0), nYDenom(0); + rIStm.ReadInt32(nXNum).ReadInt32(nXDenom).ReadInt32(nYNum).ReadInt32(nYDenom); + + if (!rIStm.good() || nXDenom <= 0 || nYDenom <= 0 || nXNum <= 0 || nYNum <= 0) + { + SAL_WARN("vcl.gdi", "Parsing error: invalid mapmode fraction"); + return false; + } + + if (nUnit < sal_Int16(MapUnit::Map100thMM) || nUnit > sal_Int16(MapUnit::LAST)) + { + SAL_WARN("vcl.gdi", "Parsing error: invalid mapmode"); + return false; + } + + rMapMode = MapMode(static_cast(nUnit), aOrg, Fraction(nXNum, nXDenom), Fraction(nYNum, nYDenom)); + + return true; +} + +static void ImplReadUnicodeComment( sal_uInt32 nStrmPos, SvStream& rIStm, OUString& rString ) +{ + sal_uInt64 nOld = rIStm.Tell(); + if ( nStrmPos ) + { + sal_uInt16 nType; + sal_uInt32 nActionSize; + std::size_t nStringLen; + + rIStm.Seek( nStrmPos ); + rIStm .ReadUInt16( nType ) + .ReadUInt32( nActionSize ); + + nStringLen = (nActionSize - 4) >> 1; + + if ( nStringLen && ( nType == GDI_UNICODE_COMMENT ) ) + rString = read_uInt16s_ToOUString(rIStm, nStringLen); + } + rIStm.Seek( nOld ); +} + +static void ImplSkipActions(SvStream& rIStm, sal_uLong nSkipCount) +{ + sal_Int32 nActionSize; + sal_Int16 nType; + for (sal_uLong i = 0; i < nSkipCount; ++i) + { + rIStm.ReadInt16(nType).ReadInt32(nActionSize); + if (!rIStm.good() || nActionSize < 4) + break; + rIStm.SeekRel(nActionSize - 4); + } +} + +static void ImplReadExtendedPolyPolygonAction(SvStream& rIStm, tools::PolyPolygon& rPolyPoly) +{ + TypeSerializer aSerializer(rIStm); + + rPolyPoly.Clear(); + sal_uInt16 nPolygonCount(0); + rIStm.ReadUInt16( nPolygonCount ); + + if (!nPolygonCount) + return; + + const size_t nMinRecordSize = sizeof(sal_uInt16); + const size_t nMaxRecords = rIStm.remainingSize() / nMinRecordSize; + if (nPolygonCount > nMaxRecords) + { + SAL_WARN("vcl.gdi", "Parsing error: " << nMaxRecords << + " max possible entries, but " << nPolygonCount << " claimed, truncating"); + nPolygonCount = nMaxRecords; + } + + for(sal_uInt16 a(0); a < nPolygonCount; a++) + { + sal_uInt16 nPointCount(0); + rIStm.ReadUInt16(nPointCount); + + const size_t nMinPolygonSize = sizeof(sal_Int32) * 2; + const size_t nMaxPolygons = rIStm.remainingSize() / nMinPolygonSize; + if (nPointCount > nMaxPolygons) + { + SAL_WARN("vcl.gdi", "Parsing error: " << nMaxPolygons << + " max possible entries, but " << nPointCount << " claimed, truncating"); + nPointCount = nMaxPolygons; + } + + tools::Polygon aCandidate(nPointCount); + + if (nPointCount) + { + for(sal_uInt16 b(0); b < nPointCount; b++) + { + aSerializer.readPoint(aCandidate[b]); + } + + sal_uInt8 bHasFlags(int(false)); + rIStm.ReadUChar( bHasFlags ); + + if(bHasFlags) + { + sal_uInt8 aPolyFlags(0); + + for(sal_uInt16 c(0); c < nPointCount; c++) + { + rIStm.ReadUChar( aPolyFlags ); + aCandidate.SetFlags(c, static_cast(aPolyFlags)); + } + } + } + + rPolyPoly.Insert(aCandidate); + } +} + +SVMConverter::SVMConverter( SvStream& rStm, GDIMetaFile& rMtf ) +{ + if( !rStm.GetError() ) + { + ImplConvertFromSVM1( rStm, rMtf ); + } +} + +namespace +{ + sal_Int32 SkipActions(sal_Int32 i, sal_Int32 nFollowingActionCount, sal_Int32 nActions) + { + sal_Int32 remainingActions = nActions - i; + if (nFollowingActionCount < 0) + nFollowingActionCount = remainingActions; + return std::min(remainingActions, nFollowingActionCount); + } + + void ClampRange(const OUString& rStr, sal_Int32& rIndex, sal_Int32& rLength, + std::vector* pDXAry = nullptr) + { + const sal_Int32 nStrLength = rStr.getLength(); + + if (rIndex < 0 || rIndex > nStrLength) + { + SAL_WARN("vcl.gdi", "inconsistent offset"); + rIndex = nStrLength; + } + + if (rLength < 0 || rLength > nStrLength - rIndex) + { + SAL_WARN("vcl.gdi", "inconsistent len"); + rLength = nStrLength - rIndex; + } + + if (pDXAry && pDXAry->size() > o3tl::make_unsigned(rLength)) + pDXAry->resize(rLength); + } +} + +#define LF_FACESIZE 32 + +void static lcl_error( SvStream& rIStm, const SvStreamEndian& nOldFormat, sal_uInt64 nPos) +{ + rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR); + rIStm.SetEndian(nOldFormat); + rIStm.Seek(nPos); + return; +} +void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ) +{ + const sal_uInt64 nPos = rIStm.Tell(); + const SvStreamEndian nOldFormat = rIStm.GetEndian(); + + rIStm.SetEndian( SvStreamEndian::LITTLE ); + + char aCode[ 5 ]; + Size aPrefSz; + + // read header + rIStm.ReadBytes(aCode, sizeof(aCode)); // Identifier + sal_Int16 nSize(0); + rIStm.ReadInt16( nSize ); // Size + sal_Int16 nVersion(0); + rIStm.ReadInt16( nVersion ); // Version + sal_Int32 nTmp32(0); + rIStm.ReadInt32( nTmp32 ); + if (nTmp32 < 0) + { + SAL_WARN("vcl.gdi", "svm: value for width should be positive"); + lcl_error(rIStm, nOldFormat, nPos); + return; + } + aPrefSz.setWidth( nTmp32 ); // PrefSize.Width() + rIStm.ReadInt32( nTmp32 ); + if (nTmp32 < 0) + { + SAL_WARN("vcl.gdi", "svm: value for height should be positive"); + lcl_error(rIStm, nOldFormat, nPos); + return; + } + aPrefSz.setHeight( nTmp32 ); // PrefSize.Height() + + // check header-magic and version + if( rIStm.GetError() + || ( nVersion != 200 ) + || ( memcmp( aCode, "SVGDI", sizeof( aCode ) ) != 0 ) ) + { + SAL_WARN("vcl.gdi", "svm: wrong check for header-magic and version"); + lcl_error(rIStm, nOldFormat, nPos); + return; + } + + LineInfo aLineInfo( LineStyle::NONE, 0 ); + std::stack> aLIStack; + ScopedVclPtrInstance< VirtualDevice > aFontVDev; + rtl_TextEncoding eActualCharSet = osl_getThreadTextEncoding(); + bool bFatLine = false; + + tools::Polygon aActionPoly; + tools::Rectangle aRect; + Point aPt, aPt1; + Size aSz; + Color aActionColor; + + sal_uInt32 nUnicodeCommentStreamPos = 0; + sal_Int32 nUnicodeCommentActionNumber = 0; + + rMtf.SetPrefSize(aPrefSz); + + MapMode aMapMode; + if (ImplReadMapMode(rIStm, aMapMode)) // MapMode + rMtf.SetPrefMapMode(aMapMode); + + sal_Int32 nActions(0); + rIStm.ReadInt32(nActions); // Action count + if (nActions < 0) + { + SAL_WARN("vcl.gdi", "svm claims negative action count (" << nActions << ")"); + nActions = 0; + } + + const size_t nMinActionSize = sizeof(sal_uInt16) + sizeof(sal_Int32); + const size_t nMaxPossibleActions = rIStm.remainingSize() / nMinActionSize; + if (o3tl::make_unsigned(nActions) > nMaxPossibleActions) + { + SAL_WARN("vcl.gdi", "svm claims more actions (" << nActions << ") than stream could provide, truncating"); + nActions = nMaxPossibleActions; + } + + size_t nLastPolygonAction(0); + + TypeSerializer aSerializer(rIStm); + + for (sal_Int32 i = 0; i < nActions && rIStm.good(); ++i) + { + sal_Int16 nType(0); + rIStm.ReadInt16(nType); + sal_Int32 nActBegin = rIStm.Tell(); + sal_Int32 nActionSize(0); + rIStm.ReadInt32(nActionSize); + + SAL_WARN_IF( ( nType > 33 ) && ( nType < 1024 ), "vcl.gdi", "Unknown GDIMetaAction while converting!" ); + + switch( nType ) + { + case GDI_PIXEL_ACTION: + { + aSerializer.readPoint(aPt); + ImplReadColor( rIStm, aActionColor ); + rMtf.AddAction( new MetaPixelAction( aPt, aActionColor ) ); + } + break; + + case GDI_POINT_ACTION: + { + aSerializer.readPoint(aPt); + rMtf.AddAction( new MetaPointAction( aPt ) ); + } + break; + + case GDI_LINE_ACTION: + { + aSerializer.readPoint(aPt); + aSerializer.readPoint(aPt1); + rMtf.AddAction( new MetaLineAction( aPt, aPt1, aLineInfo ) ); + } + break; + + case GDI_LINEJOIN_ACTION : + { + sal_Int16 nLineJoin(0); + rIStm.ReadInt16( nLineJoin ); + aLineInfo.SetLineJoin(static_cast(nLineJoin)); + } + break; + + case GDI_LINECAP_ACTION : + { + sal_Int16 nLineCap(0); + rIStm.ReadInt16( nLineCap ); + aLineInfo.SetLineCap(static_cast(nLineCap)); + } + break; + + case GDI_LINEDASHDOT_ACTION : + { + sal_Int16 a(0); + sal_Int32 b(0); + + rIStm.ReadInt16( a ); aLineInfo.SetDashCount(a); + rIStm.ReadInt32( b ); aLineInfo.SetDashLen(b); + rIStm.ReadInt16( a ); aLineInfo.SetDotCount(a); + rIStm.ReadInt32( b ); aLineInfo.SetDotLen(b); + rIStm.ReadInt32( b ); aLineInfo.SetDistance(b); + + if(((aLineInfo.GetDashCount() && aLineInfo.GetDashLen()) + || (aLineInfo.GetDotCount() && aLineInfo.GetDotLen())) + && aLineInfo.GetDistance()) + { + aLineInfo.SetStyle(LineStyle::Dash); + } + } + break; + + case GDI_EXTENDEDPOLYGON_ACTION : + { + // read the tools::PolyPolygon in every case + tools::PolyPolygon aInputPolyPolygon; + ImplReadExtendedPolyPolygonAction(rIStm, aInputPolyPolygon); + + // now check if it can be set somewhere + if(nLastPolygonAction < rMtf.GetActionSize()) + { + MetaPolyLineAction* pPolyLineAction = dynamic_cast< MetaPolyLineAction* >(rMtf.GetAction(nLastPolygonAction)); + + if(pPolyLineAction) + { + // replace MetaPolyLineAction when we have a single polygon. Do not rely on the + // same point count; the originally written GDI_POLYLINE_ACTION may have been + // Subdivided for better quality for older usages + if(1 == aInputPolyPolygon.Count()) + { + rMtf.ReplaceAction( + new MetaPolyLineAction( + aInputPolyPolygon.GetObject(0), + pPolyLineAction->GetLineInfo()), + nLastPolygonAction); + } + } + else + { + MetaPolyPolygonAction* pPolyPolygonAction = dynamic_cast< MetaPolyPolygonAction* >(rMtf.GetAction(nLastPolygonAction)); + + if(pPolyPolygonAction) + { + // replace MetaPolyPolygonAction when we have a curved polygon. Do rely on the + // same sub-polygon count + if(pPolyPolygonAction->GetPolyPolygon().Count() == aInputPolyPolygon.Count()) + { + rMtf.ReplaceAction( + new MetaPolyPolygonAction( + aInputPolyPolygon), + nLastPolygonAction); + } + } + else + { + MetaPolygonAction* pPolygonAction = dynamic_cast< MetaPolygonAction* >(rMtf.GetAction(nLastPolygonAction)); + + if(pPolygonAction) + { + // replace MetaPolygonAction + if(1 == aInputPolyPolygon.Count()) + { + rMtf.ReplaceAction( + new MetaPolygonAction( + aInputPolyPolygon.GetObject(0)), + nLastPolygonAction); + } + } + } + } + } + } + break; + + case GDI_RECT_ACTION: + { + ImplReadRect( rIStm, aRect ); + sal_Int32 nTmp(0), nTmp1(0); + rIStm.ReadInt32( nTmp ).ReadInt32( nTmp1 ); + + if( nTmp || nTmp1 ) + rMtf.AddAction( new MetaRoundRectAction( aRect, nTmp, nTmp1 ) ); + else + { + rMtf.AddAction( new MetaRectAction( aRect ) ); + + if( bFatLine ) + rMtf.AddAction( new MetaPolyLineAction( aRect, aLineInfo ) ); + } + } + break; + + case GDI_ELLIPSE_ACTION: + { + ImplReadRect( rIStm, aRect ); + + if( bFatLine ) + { + const tools::Polygon aPoly( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 ); + + rMtf.AddAction( new MetaPushAction( vcl::PushFlags::LINECOLOR ) ); + rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) ); + rMtf.AddAction( new MetaPolygonAction( aPoly ) ); + rMtf.AddAction( new MetaPopAction() ); + rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) ); + } + else + rMtf.AddAction( new MetaEllipseAction( aRect ) ); + } + break; + + case GDI_ARC_ACTION: + { + ImplReadRect( rIStm, aRect ); + aSerializer.readPoint(aPt); + aSerializer.readPoint(aPt1); + + if( bFatLine ) + { + const tools::Polygon aPoly( aRect, aPt, aPt1, PolyStyle::Arc ); + + rMtf.AddAction( new MetaPushAction( vcl::PushFlags::LINECOLOR ) ); + rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) ); + rMtf.AddAction( new MetaPolygonAction( aPoly ) ); + rMtf.AddAction( new MetaPopAction() ); + rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) ); + } + else + rMtf.AddAction( new MetaArcAction( aRect, aPt, aPt1 ) ); + } + break; + + case GDI_PIE_ACTION: + { + ImplReadRect( rIStm, aRect ); + aSerializer.readPoint(aPt); + aSerializer.readPoint(aPt1); + + if( bFatLine ) + { + const tools::Polygon aPoly( aRect, aPt, aPt1, PolyStyle::Pie ); + + rMtf.AddAction( new MetaPushAction( vcl::PushFlags::LINECOLOR ) ); + rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) ); + rMtf.AddAction( new MetaPolygonAction( aPoly ) ); + rMtf.AddAction( new MetaPopAction() ); + rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) ); + } + else + rMtf.AddAction( new MetaPieAction( aRect, aPt, aPt1 ) ); + } + break; + + case GDI_INVERTRECT_ACTION: + case GDI_HIGHLIGHTRECT_ACTION: + { + ImplReadRect( rIStm, aRect ); + rMtf.AddAction( new MetaPushAction( vcl::PushFlags::RASTEROP ) ); + rMtf.AddAction( new MetaRasterOpAction( RasterOp::Invert ) ); + rMtf.AddAction( new MetaRectAction( aRect ) ); + rMtf.AddAction( new MetaPopAction() ); + } + break; + + case GDI_POLYLINE_ACTION: + { + if (ImplReadPoly(rIStm, aActionPoly)) + { + nLastPolygonAction = rMtf.GetActionSize(); + + if( bFatLine ) + rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) ); + else + rMtf.AddAction( new MetaPolyLineAction( aActionPoly ) ); + } + } + break; + + case GDI_POLYGON_ACTION: + { + if (ImplReadPoly(rIStm, aActionPoly)) + { + if( bFatLine ) + { + rMtf.AddAction( new MetaPushAction( vcl::PushFlags::LINECOLOR ) ); + rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) ); + rMtf.AddAction( new MetaPolygonAction( aActionPoly ) ); + rMtf.AddAction( new MetaPopAction() ); + rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) ); + } + else + { + nLastPolygonAction = rMtf.GetActionSize(); + rMtf.AddAction( new MetaPolygonAction( aActionPoly ) ); + } + } + } + break; + + case GDI_POLYPOLYGON_ACTION: + { + tools::PolyPolygon aPolyPoly; + + if (ImplReadPolyPoly(rIStm, aPolyPoly)) + { + if( bFatLine ) + { + rMtf.AddAction( new MetaPushAction( vcl::PushFlags::LINECOLOR ) ); + rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) ); + rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) ); + rMtf.AddAction( new MetaPopAction() ); + + for( sal_uInt16 nPoly = 0, nCount = aPolyPoly.Count(); nPoly < nCount; nPoly++ ) + rMtf.AddAction( new MetaPolyLineAction( aPolyPoly[ nPoly ], aLineInfo ) ); + } + else + { + nLastPolygonAction = rMtf.GetActionSize(); + rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) ); + } + } + } + break; + + case GDI_FONT_ACTION: + { + vcl::Font aFont; + char aName[LF_FACESIZE+1]; + + ImplReadColor( rIStm, aActionColor ); aFont.SetColor( aActionColor ); + ImplReadColor( rIStm, aActionColor ); aFont.SetFillColor( aActionColor ); + size_t nRet = rIStm.ReadBytes(aName, LF_FACESIZE); + aName[nRet] = 0; + aFont.SetFamilyName( OUString( aName, strlen(aName), rIStm.GetStreamCharSet() ) ); + + sal_Int32 nWidth(0), nHeight(0); + rIStm.ReadInt32(nWidth).ReadInt32(nHeight); + sal_Int16 nCharOrient(0), nLineOrient(0); + rIStm.ReadInt16(nCharOrient).ReadInt16(nLineOrient); + sal_Int16 nCharSet(0), nFamily(0), nPitch(0), nAlign(0), nWeight(0), nUnderline(0), nStrikeout(0); + rIStm.ReadInt16(nCharSet).ReadInt16(nFamily).ReadInt16(nPitch).ReadInt16(nAlign).ReadInt16(nWeight).ReadInt16(nUnderline).ReadInt16(nStrikeout); + bool bItalic(false), bOutline(false), bShadow(false), bTransparent(false); + rIStm.ReadCharAsBool(bItalic).ReadCharAsBool(bOutline).ReadCharAsBool(bShadow).ReadCharAsBool(bTransparent); + + aFont.SetFontSize( Size( nWidth, nHeight ) ); + aFont.SetCharSet( static_cast(nCharSet) ); + aFont.SetFamily( static_cast(nFamily & SAL_MAX_ENUM) ); + aFont.SetPitch( static_cast(nPitch & SAL_MAX_ENUM) ); + aFont.SetAlignment( static_cast(nAlign & SAL_MAX_ENUM) ); + aFont.SetWeight( ( nWeight == 1 ) ? WEIGHT_LIGHT : ( nWeight == 2 ) ? WEIGHT_NORMAL : + ( nWeight == 3 ) ? WEIGHT_BOLD : WEIGHT_DONTKNOW ); + aFont.SetUnderline( static_cast(nUnderline & SAL_MAX_ENUM) ); + aFont.SetStrikeout( static_cast(nStrikeout & SAL_MAX_ENUM) ); + aFont.SetItalic( bItalic ? ITALIC_NORMAL : ITALIC_NONE ); + aFont.SetOutline( bOutline ); + aFont.SetShadow( bShadow ); + aFont.SetOrientation( Degree10(nLineOrient) ); + aFont.SetTransparent( bTransparent ); + + eActualCharSet = aFont.GetCharSet(); + if ( eActualCharSet == RTL_TEXTENCODING_DONTKNOW ) + eActualCharSet = osl_getThreadTextEncoding(); + + rMtf.AddAction( new MetaFontAction( aFont ) ); + rMtf.AddAction( new MetaTextAlignAction( aFont.GetAlignment() ) ); + rMtf.AddAction( new MetaTextColorAction( aFont.GetColor() ) ); + rMtf.AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) ); + + // #106172# Track font relevant data in shadow VDev + aFontVDev->SetFont( aFont ); + } + break; + + case GDI_TEXT_ACTION: + { + sal_Int32 nIndex(0), nLen(0), nTmp(0); + aSerializer.readPoint(aPt); + rIStm.ReadInt32( nIndex ).ReadInt32( nLen ).ReadInt32( nTmp ); + if (nTmp > 0) + { + OString aByteStr = read_uInt8s_ToOString(rIStm, nTmp); + sal_uInt8 nTerminator = 0; + rIStm.ReadUChar( nTerminator ); + SAL_WARN_IF( nTerminator != 0, "vcl.gdi", "expected string to be NULL terminated" ); + + OUString aStr(OStringToOUString(aByteStr, eActualCharSet)); + if ( nUnicodeCommentActionNumber == i ) + ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr ); + ClampRange(aStr, nIndex, nLen); + rMtf.AddAction( new MetaTextAction( aPt, aStr, nIndex, nLen ) ); + } + + if (nActionSize < 24) + rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR); + else + rIStm.Seek(nActBegin + nActionSize); + } + break; + + case GDI_TEXTARRAY_ACTION: + { + sal_Int32 nIndex(0), nLen(0), nAryLen(0), nTmp(0); + aSerializer.readPoint(aPt); + rIStm.ReadInt32( nIndex ).ReadInt32( nLen ).ReadInt32( nTmp ).ReadInt32( nAryLen ); + if (nTmp > 0) + { + OString aByteStr = read_uInt8s_ToOString(rIStm, nTmp); + sal_uInt8 nTerminator = 0; + rIStm.ReadUChar( nTerminator ); + SAL_WARN_IF( nTerminator != 0, "vcl.gdi", "expected string to be NULL terminated" ); + + OUString aStr(OStringToOUString(aByteStr, eActualCharSet)); + + std::vector aDXAry; + if (nAryLen > 0) + { + const size_t nMinRecordSize = sizeof(sal_Int32); + const size_t nMaxRecords = rIStm.remainingSize() / nMinRecordSize; + if (o3tl::make_unsigned(nAryLen) > nMaxRecords) + { + SAL_WARN("vcl.gdi", "Parsing error: " << nMaxRecords << + " max possible entries, but " << nAryLen << " claimed, truncating"); + nAryLen = nMaxRecords; + } + + sal_Int32 nStrLen( aStr.getLength() ); + + sal_Int32 nDXAryLen = std::max(nAryLen, nStrLen); + + if (nDXAryLen < nLen) + { + //MetaTextArrayAction ctor expects pDXAry to be >= nLen if set, so if this can't + //be achieved, don't read it, it's utterly broken. + SAL_WARN("vcl.gdi", "dxary too short, discarding completely"); + rIStm.SeekRel(sizeof(sal_Int32) * nDXAryLen); + nLen = 0; + nIndex = 0; + } + else + { + aDXAry.resize(nDXAryLen); + + for (sal_Int32 j = 0; j < nAryLen; ++j) + { + rIStm.ReadInt32( nTmp ); + aDXAry[ j ] = nTmp; + } + + // #106172# Add last DX array elem, if missing + if( nAryLen != nStrLen ) + { + if (nAryLen+1 == nStrLen && nIndex >= 0) + { + std::vector aTmpAry; + + aFontVDev->GetTextArray( aStr, &aTmpAry, nIndex, nLen ); + + if (aTmpAry.size() < o3tl::make_unsigned(nStrLen)) + SAL_WARN("vcl.gdi", "TextArray too short to recover missing element"); + else + { + // now, the difference between the + // last and the second last DX array + // is the advancement for the last + // glyph. Thus, to complete our meta + // action's DX array, just add that + // difference to last elem and store + // in very last. + if( nStrLen > 1 ) + aDXAry[ nStrLen-1 ] = aDXAry[ nStrLen-2 ] + aTmpAry[ nStrLen-1 ] - aTmpAry[ nStrLen-2 ]; + else + aDXAry[ nStrLen-1 ] = aTmpAry[ nStrLen-1 ]; // len=1: 0th position taken to be 0 + } + } +#ifdef DBG_UTIL + else + OSL_FAIL("More than one DX array element missing on SVM import"); +#endif + } + } + } + if ( nUnicodeCommentActionNumber == i ) + ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr ); + ClampRange(aStr, nIndex, nLen, &aDXAry); + rMtf.AddAction( new MetaTextArrayAction( aPt, aStr, aDXAry, nIndex, nLen ) ); + } + + if (nActionSize < 24) + rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR); + else + rIStm.Seek(nActBegin + nActionSize); + } + break; + + case GDI_STRETCHTEXT_ACTION: + { + sal_Int32 nIndex(0), nLen(0), nWidth(0), nTmp(0); + + aSerializer.readPoint(aPt); + rIStm.ReadInt32( nIndex ).ReadInt32( nLen ).ReadInt32( nTmp ).ReadInt32( nWidth ); + if (nTmp > 0) + { + OString aByteStr = read_uInt8s_ToOString(rIStm, nTmp); + sal_uInt8 nTerminator = 0; + rIStm.ReadUChar( nTerminator ); + SAL_WARN_IF( nTerminator != 0, "vcl.gdi", "expected string to be NULL terminated" ); + + OUString aStr(OStringToOUString(aByteStr, eActualCharSet)); + if ( nUnicodeCommentActionNumber == i ) + ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr ); + ClampRange(aStr, nIndex, nLen); + rMtf.AddAction( new MetaStretchTextAction( aPt, nWidth, aStr, nIndex, nLen ) ); + } + + if (nActionSize < 28) + rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR); + else + rIStm.Seek(nActBegin + nActionSize); + } + break; + + case GDI_BITMAP_ACTION: + { + Bitmap aBmp; + + aSerializer.readPoint(aPt); + ReadDIB(aBmp, rIStm, true); + rMtf.AddAction( new MetaBmpAction( aPt, aBmp ) ); + } + break; + + case GDI_BITMAPSCALE_ACTION: + { + Bitmap aBmp; + + aSerializer.readPoint(aPt); + aSerializer.readSize(aSz); + ReadDIB(aBmp, rIStm, true); + rMtf.AddAction( new MetaBmpScaleAction( aPt, aSz, aBmp ) ); + } + break; + + case GDI_BITMAPSCALEPART_ACTION: + { + Bitmap aBmp; + Size aSz2; + + aSerializer.readPoint(aPt); + aSerializer.readSize(aSz); + aSerializer.readPoint(aPt1); + aSerializer.readSize(aSz2); + ReadDIB(aBmp, rIStm, true); + rMtf.AddAction( new MetaBmpScalePartAction( aPt, aSz, aPt1, aSz2, aBmp ) ); + } + break; + + case GDI_PEN_ACTION: + { + ImplReadColor( rIStm, aActionColor ); + + sal_Int32 nPenWidth(0); + sal_Int16 nPenStyle(0); + rIStm.ReadInt32( nPenWidth ).ReadInt16( nPenStyle ); + + aLineInfo.SetStyle( nPenStyle ? LineStyle::Solid : LineStyle::NONE ); + aLineInfo.SetWidth( nPenWidth ); + bFatLine = nPenStyle && !aLineInfo.IsDefault(); + + rMtf.AddAction( new MetaLineColorAction( aActionColor, nPenStyle != 0 ) ); + } + break; + + case GDI_FILLBRUSH_ACTION: + { + ImplReadColor( rIStm, aActionColor ); + rIStm.SeekRel( 6 ); + sal_Int16 nBrushStyle(0); + rIStm.ReadInt16( nBrushStyle ); + rMtf.AddAction( new MetaFillColorAction( aActionColor, nBrushStyle != 0 ) ); + rIStm.SeekRel( 2 ); + } + break; + + case GDI_MAPMODE_ACTION: + { + if (ImplReadMapMode(rIStm, aMapMode)) + { + rMtf.AddAction(new MetaMapModeAction(aMapMode)); + + // #106172# Track font relevant data in shadow VDev + aFontVDev->SetMapMode(aMapMode); + }; + } + break; + + case GDI_CLIPREGION_ACTION: + { + vcl::Region aRegion; + bool bClip = false; + + sal_Int16 nRegType(0); + sal_Int16 bIntersect(0); + rIStm.ReadInt16( nRegType ).ReadInt16( bIntersect ); + ImplReadRect( rIStm, aRect ); + + switch( nRegType ) + { + case 0: + break; + + case 1: + { + tools::Rectangle aRegRect; + + ImplReadRect( rIStm, aRegRect ); + aRegion = vcl::Region( aRegRect ); + bClip = true; + } + break; + + case 2: + { + if (ImplReadPoly(rIStm, aActionPoly)) + { + aRegion = vcl::Region( aActionPoly ); + bClip = true; + } + } + break; + + case 3: + { + bool bSuccess = true; + tools::PolyPolygon aPolyPoly; + sal_Int32 nPolyCount32(0); + rIStm.ReadInt32(nPolyCount32); + sal_uInt16 nPolyCount(nPolyCount32); + + for (sal_uInt16 j = 0; j < nPolyCount && rIStm.good(); ++j) + { + if (!ImplReadPoly(rIStm, aActionPoly)) + { + bSuccess = false; + break; + } + aPolyPoly.Insert(aActionPoly); + } + + if (bSuccess) + { + aRegion = vcl::Region( aPolyPoly ); + bClip = true; + } + } + break; + } + + if( bIntersect ) + aRegion.Intersect( aRect ); + + rMtf.AddAction( new MetaClipRegionAction( aRegion, bClip ) ); + } + break; + + case GDI_MOVECLIPREGION_ACTION: + { + sal_Int32 nTmp(0), nTmp1(0); + rIStm.ReadInt32( nTmp ).ReadInt32( nTmp1 ); + rMtf.AddAction( new MetaMoveClipRegionAction( nTmp, nTmp1 ) ); + } + break; + + case GDI_ISECTCLIPREGION_ACTION: + { + ImplReadRect( rIStm, aRect ); + rMtf.AddAction( new MetaISectRectClipRegionAction( aRect ) ); + } + break; + + case GDI_RASTEROP_ACTION: + { + RasterOp eRasterOp; + + sal_Int16 nRasterOp(0); + rIStm.ReadInt16( nRasterOp ); + + switch( nRasterOp ) + { + case 1: + eRasterOp = RasterOp::Invert; + break; + + case 4: + case 5: + eRasterOp = RasterOp::Xor; + break; + + default: + eRasterOp = RasterOp::OverPaint; + break; + } + + rMtf.AddAction( new MetaRasterOpAction( eRasterOp ) ); + } + break; + + case GDI_PUSH_ACTION: + { + aLIStack.push(aLineInfo); + rMtf.AddAction( new MetaPushAction( vcl::PushFlags::ALL ) ); + + // #106172# Track font relevant data in shadow VDev + aFontVDev->Push(); + } + break; + + case GDI_POP_ACTION: + { + + std::optional xLineInfo; + if (!aLIStack.empty()) + { + xLineInfo = std::move(aLIStack.top()); + aLIStack.pop(); + } + + // restore line info + if (xLineInfo) + { + aLineInfo = *xLineInfo; + xLineInfo.reset(); + bFatLine = ( LineStyle::NONE != aLineInfo.GetStyle() ) && !aLineInfo.IsDefault(); + } + + rMtf.AddAction( new MetaPopAction() ); + + // #106172# Track font relevant data in shadow VDev + aFontVDev->Pop(); + } + break; + + case GDI_GRADIENT_ACTION: + { + ImplReadRect( rIStm, aRect ); + + sal_Int16 nStyle(0); + rIStm.ReadInt16( nStyle ); + + Color aStartCol, aEndCol; + ImplReadColor( rIStm, aStartCol ); + ImplReadColor( rIStm, aEndCol ); + + sal_Int16 nAngle(0), nBorder(0), nOfsX(0), nOfsY(0), nIntensityStart(0), nIntensityEnd(0); + rIStm.ReadInt16( nAngle ).ReadInt16( nBorder ).ReadInt16( nOfsX ).ReadInt16( nOfsY ).ReadInt16( nIntensityStart ).ReadInt16( nIntensityEnd ); + + Gradient aGrad( static_cast(nStyle), aStartCol, aEndCol ); + + aGrad.SetAngle( Degree10(nAngle) ); + aGrad.SetBorder( nBorder ); + aGrad.SetOfsX( nOfsX ); + aGrad.SetOfsY( nOfsY ); + aGrad.SetStartIntensity( nIntensityStart ); + aGrad.SetEndIntensity( nIntensityEnd ); + rMtf.AddAction( new MetaGradientAction( aRect, aGrad ) ); + } + break; + + case GDI_TRANSPARENT_COMMENT: + { + tools::PolyPolygon aPolyPoly; + sal_Int32 nFollowingActionCount(0); + sal_Int16 nTrans(0); + + ReadPolyPolygon( rIStm, aPolyPoly ); + rIStm.ReadInt16( nTrans ).ReadInt32( nFollowingActionCount ); + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaTransparentAction( aPolyPoly, nTrans ) ); + + i = SkipActions(i, nFollowingActionCount, nActions); + } + break; + + case GDI_FLOATTRANSPARENT_COMMENT: + { + GDIMetaFile aMtf; + Point aPos; + Size aSize; + Gradient aGradient; + sal_Int32 nFollowingActionCount(0); + + SvmReader aReader( rIStm ); + aReader.Read( aMtf ); + aSerializer.readPoint(aPos); + aSerializer.readSize(aSize); + aSerializer.readGradient(aGradient); + rIStm.ReadInt32( nFollowingActionCount ); + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaFloatTransparentAction( aMtf, aPos, aSize, aGradient ) ); + + i = SkipActions(i, nFollowingActionCount, nActions); + } + break; + + case GDI_HATCH_COMMENT: + { + tools::PolyPolygon aPolyPoly; + Hatch aHatch; + sal_Int32 nFollowingActionCount(0); + + ReadPolyPolygon( rIStm, aPolyPoly ); + ReadHatch( rIStm, aHatch ); + rIStm.ReadInt32( nFollowingActionCount ); + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaHatchAction( aPolyPoly, aHatch ) ); + + i = SkipActions(i, nFollowingActionCount, nActions); + } + break; + + case GDI_REFPOINT_COMMENT: + { + Point aRefPoint; + bool bSet(false); + sal_Int32 nFollowingActionCount(0); + + aSerializer.readPoint(aRefPoint); + rIStm.ReadCharAsBool( bSet ).ReadInt32( nFollowingActionCount ); + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaRefPointAction( aRefPoint, bSet ) ); + + i = SkipActions(i, nFollowingActionCount, nActions); + + // #106172# Track font relevant data in shadow VDev + if( bSet ) + aFontVDev->SetRefPoint( aRefPoint ); + else + aFontVDev->SetRefPoint(); + } + break; + + case GDI_TEXTLINECOLOR_COMMENT: + { + Color aColor; + bool bSet(false); + sal_Int32 nFollowingActionCount(0); + + aSerializer.readColor(aColor); + rIStm.ReadCharAsBool( bSet ).ReadInt32( nFollowingActionCount ); + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaTextLineColorAction( aColor, bSet ) ); + + i = SkipActions(i, nFollowingActionCount, nActions); + } + break; + + case GDI_TEXTLINE_COMMENT: + { + Point aStartPt; + sal_Int32 nWidth(0); + sal_uInt32 nStrikeout(0); + sal_uInt32 nUnderline(0); + sal_Int32 nFollowingActionCount(0); + + aSerializer.readPoint(aStartPt); + rIStm.ReadInt32(nWidth ).ReadUInt32(nStrikeout).ReadUInt32(nUnderline).ReadInt32(nFollowingActionCount); + ImplSkipActions(rIStm, nFollowingActionCount); + rMtf.AddAction( new MetaTextLineAction( aStartPt, nWidth, + static_cast(nStrikeout & SAL_MAX_ENUM), + static_cast(nUnderline & SAL_MAX_ENUM), + LINESTYLE_NONE ) ); + + i = SkipActions(i, nFollowingActionCount, nActions); + } + break; + + case GDI_GRADIENTEX_COMMENT: + { + tools::PolyPolygon aPolyPoly; + Gradient aGradient; + sal_Int32 nFollowingActionCount(0); + + ReadPolyPolygon( rIStm, aPolyPoly ); + aSerializer.readGradient(aGradient); + rIStm.ReadInt32( nFollowingActionCount ); + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction( new MetaGradientExAction( aPolyPoly, aGradient ) ); + + i = SkipActions(i, nFollowingActionCount, nActions); + } + break; + + case GDI_COMMENT_COMMENT: + { + std::vector aData; + + OString aComment = read_uInt16_lenPrefixed_uInt8s_ToOString(rIStm); + sal_Int32 nValue(0); + sal_uInt32 nDataSize(0); + rIStm.ReadInt32(nValue).ReadUInt32(nDataSize); + + if (nDataSize) + { + const size_t nMaxPossibleData = rIStm.remainingSize(); + if (nDataSize > nMaxPossibleActions) + { + SAL_WARN("vcl.gdi", "svm record claims to have: " << nDataSize << " data, but only " << nMaxPossibleData << " possible"); + nDataSize = nMaxPossibleActions; + } + aData.resize(nDataSize); + nDataSize = rIStm.ReadBytes(aData.data(), nDataSize); + } + + sal_Int32 nFollowingActionCount(0); + rIStm.ReadInt32(nFollowingActionCount); + ImplSkipActions( rIStm, nFollowingActionCount ); + rMtf.AddAction(new MetaCommentAction(aComment, nValue, aData.data(), nDataSize)); + + i = SkipActions(i, nFollowingActionCount, nActions); + } + break; + + case GDI_UNICODE_COMMENT: + { + nUnicodeCommentActionNumber = i + 1; + nUnicodeCommentStreamPos = rIStm.Tell() - 6; + if (nActionSize < 4) + rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR); + else + rIStm.SeekRel(nActionSize - 4); + } + break; + + default: + if (nActionSize < 4) + rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR); + else + rIStm.SeekRel(nActionSize - 4); + break; + } + } + + rIStm.SetEndian( nOldFormat ); +} + +bool TestImportSVM(SvStream& rStream) +{ + GDIMetaFile aGDIMetaFile; + SvmReader aReader(rStream); + aReader.Read(aGDIMetaFile); + ScopedVclPtrInstance aVDev; + aVDev->SetTextRenderModeForResolutionIndependentLayout(true); + try + { + aGDIMetaFile.Play(*aVDev); + } + catch (const boost::bad_rational&) + { + return false; + } + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/svm/SvmConverter.hxx b/vcl/source/filter/svm/SvmConverter.hxx new file mode 100644 index 000000000..23185dc04 --- /dev/null +++ b/vcl/source/filter/svm/SvmConverter.hxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SVMCONVERTER_HXX +#define INCLUDED_VCL_INC_SVMCONVERTER_HXX + +#include +#include + +#define GDI_PIXEL_ACTION 1 +#define GDI_POINT_ACTION 2 +#define GDI_LINE_ACTION 3 +#define GDI_RECT_ACTION 4 +#define GDI_ELLIPSE_ACTION 5 +#define GDI_ARC_ACTION 6 +#define GDI_PIE_ACTION 7 +#define GDI_INVERTRECT_ACTION 8 +#define GDI_HIGHLIGHTRECT_ACTION 9 +#define GDI_POLYLINE_ACTION 10 +#define GDI_POLYGON_ACTION 11 +#define GDI_POLYPOLYGON_ACTION 12 +#define GDI_TEXT_ACTION 13 +#define GDI_TEXTARRAY_ACTION 14 +#define GDI_STRETCHTEXT_ACTION 15 +#define GDI_BITMAP_ACTION 17 +#define GDI_BITMAPSCALE_ACTION 18 +#define GDI_PEN_ACTION 19 +#define GDI_FONT_ACTION 20 +#define GDI_FILLBRUSH_ACTION 22 +#define GDI_MAPMODE_ACTION 23 +#define GDI_CLIPREGION_ACTION 24 +#define GDI_RASTEROP_ACTION 25 +#define GDI_PUSH_ACTION 26 +#define GDI_POP_ACTION 27 +#define GDI_MOVECLIPREGION_ACTION 28 +#define GDI_ISECTCLIPREGION_ACTION 29 +#define GDI_BITMAPSCALEPART_ACTION 32 +#define GDI_GRADIENT_ACTION 33 + +#define GDI_TRANSPARENT_COMMENT 1024 +#define GDI_HATCH_COMMENT 1025 +#define GDI_REFPOINT_COMMENT 1026 +#define GDI_TEXTLINECOLOR_COMMENT 1027 +#define GDI_TEXTLINE_COMMENT 1028 +#define GDI_FLOATTRANSPARENT_COMMENT 1029 +#define GDI_GRADIENTEX_COMMENT 1030 +#define GDI_COMMENT_COMMENT 1031 +#define GDI_UNICODE_COMMENT 1032 + +#define GDI_LINEJOIN_ACTION 1033 +#define GDI_EXTENDEDPOLYGON_ACTION 1034 +#define GDI_LINEDASHDOT_ACTION 1035 + +#define GDI_LINECAP_ACTION 1036 + +/** + * Converts old SVGDI aka SVM1 format data to current VCLMTF aka SVM2 format metafile data. + */ +class SVMConverter +{ +private: + static void ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ); + +public: + SVMConverter( SvStream& rIStm, GDIMetaFile& rMtf ); + +private: + SVMConverter( const SVMConverter& ) = delete; + SVMConverter& operator=( const SVMConverter& ) = delete; +}; + +extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportSVM(SvStream& rStream); + +#endif // INCLUDED_VCL_INC_SVMCONVERTER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/svm/SvmReader.cxx b/vcl/source/filter/svm/SvmReader.cxx new file mode 100644 index 000000000..f02451ea3 --- /dev/null +++ b/vcl/source/filter/svm/SvmReader.cxx @@ -0,0 +1,1438 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "SvmConverter.hxx" + +namespace +{ +class DepthGuard +{ +private: + ImplMetaReadData& m_rData; + rtl_TextEncoding m_eOrigCharSet; + +public: + DepthGuard(ImplMetaReadData& rData, SvStream const& rIStm) + : m_rData(rData) + , m_eOrigCharSet(m_rData.meActualCharSet) + { + ++m_rData.mnParseDepth; + m_rData.meActualCharSet = rIStm.GetStreamCharSet(); + } + bool TooDeep() const { return m_rData.mnParseDepth > 1024; } + ~DepthGuard() + { + --m_rData.mnParseDepth; + m_rData.meActualCharSet = m_eOrigCharSet; + } +}; +} + +SvmReader::SvmReader(SvStream& rIStm) + : mrStream(rIStm) +{ +} + +SvStream& SvmReader::Read(GDIMetaFile& rMetaFile, ImplMetaReadData* pData) +{ + if (mrStream.GetError()) + { + SAL_WARN("vcl.gdi", "Stream error: " << mrStream.GetError()); + return mrStream; + } + + sal_uInt64 nStmPos = mrStream.Tell(); + SvStreamEndian nOldFormat = mrStream.GetEndian(); + + mrStream.SetEndian(SvStreamEndian::LITTLE); + + try + { + char aId[7]; + aId[0] = 0; + aId[6] = 0; + mrStream.ReadBytes(aId, 6); + if (mrStream.good() && !strcmp(aId, "VCLMTF")) + { + // new format + sal_uInt32 nStmCompressMode = 0; + sal_uInt32 nCount = 0; + std::unique_ptr pCompat(new VersionCompatRead(mrStream)); + + mrStream.ReadUInt32(nStmCompressMode); + TypeSerializer aSerializer(mrStream); + MapMode aMapMode; + aSerializer.readMapMode(aMapMode); + rMetaFile.SetPrefMapMode(aMapMode); + Size aSize; + aSerializer.readSize(aSize); + rMetaFile.SetPrefSize(aSize); + mrStream.ReadUInt32(nCount); + + pCompat.reset(); // destructor writes stuff into the header + + std::unique_ptr xReadData; + if (!pData) + { + xReadData.reset(new ImplMetaReadData); + pData = xReadData.get(); + } + DepthGuard aDepthGuard(*pData, mrStream); + + if (aDepthGuard.TooDeep()) + throw std::runtime_error("too much recursion"); + + for (sal_uInt32 nAction = 0; (nAction < nCount) && !mrStream.eof(); nAction++) + { + rtl::Reference pAction = MetaActionHandler(pData); + if (pAction) + { + if (pAction->GetType() == MetaActionType::COMMENT) + { + MetaCommentAction* pCommentAct + = static_cast(pAction.get()); + + if (pCommentAct->GetComment() == "EMF_PLUS") + rMetaFile.UseCanvas(true); + } + rMetaFile.AddAction(pAction); + } + } + } + else + { + mrStream.Seek(nStmPos); + SVMConverter(mrStream, rMetaFile); + } + } + catch (...) + { + SAL_WARN("vcl", "GDIMetaFile exception during load"); + mrStream.SetError(SVSTREAM_FILEFORMAT_ERROR); + }; + + // check for errors + if (mrStream.GetError()) + { + rMetaFile.Clear(); + mrStream.Seek(nStmPos); + } + + mrStream.SetEndian(nOldFormat); + return mrStream; +} + +rtl::Reference SvmReader::MetaActionHandler(ImplMetaReadData* pData) +{ + rtl::Reference pAction; + sal_uInt16 nTmp = 0; + mrStream.ReadUInt16(nTmp); + MetaActionType nType = static_cast(nTmp); + + switch (nType) + { + case MetaActionType::NONE: + return DefaultHandler(); + case MetaActionType::PIXEL: + return PixelHandler(); + case MetaActionType::POINT: + return PointHandler(); + case MetaActionType::LINE: + return LineHandler(); + case MetaActionType::RECT: + return RectHandler(); + case MetaActionType::ROUNDRECT: + return RoundRectHandler(); + case MetaActionType::ELLIPSE: + return EllipseHandler(); + case MetaActionType::ARC: + return ArcHandler(); + case MetaActionType::PIE: + return PieHandler(); + case MetaActionType::CHORD: + return ChordHandler(); + case MetaActionType::POLYLINE: + return PolyLineHandler(); + case MetaActionType::POLYGON: + return PolygonHandler(); + case MetaActionType::POLYPOLYGON: + return PolyPolygonHandler(); + case MetaActionType::TEXT: + return TextHandler(pData); + case MetaActionType::TEXTARRAY: + return TextArrayHandler(pData); + case MetaActionType::STRETCHTEXT: + return StretchTextHandler(pData); + case MetaActionType::TEXTRECT: + return TextRectHandler(pData); + case MetaActionType::TEXTLINE: + return TextLineHandler(); + case MetaActionType::BMP: + return BmpHandler(); + case MetaActionType::BMPSCALE: + return BmpScaleHandler(); + case MetaActionType::BMPSCALEPART: + return BmpScalePartHandler(); + case MetaActionType::BMPEX: + return BmpExHandler(); + case MetaActionType::BMPEXSCALE: + return BmpExScaleHandler(); + case MetaActionType::BMPEXSCALEPART: + return BmpExScalePartHandler(); + case MetaActionType::MASK: + return MaskHandler(); + case MetaActionType::MASKSCALE: + return MaskScaleHandler(); + case MetaActionType::MASKSCALEPART: + return MaskScalePartHandler(); + case MetaActionType::GRADIENT: + return GradientHandler(); + case MetaActionType::GRADIENTEX: + return GradientExHandler(); + case MetaActionType::HATCH: + return HatchHandler(); + case MetaActionType::WALLPAPER: + return WallpaperHandler(); + case MetaActionType::CLIPREGION: + return ClipRegionHandler(); + case MetaActionType::ISECTRECTCLIPREGION: + return ISectRectClipRegionHandler(); + case MetaActionType::ISECTREGIONCLIPREGION: + return ISectRegionClipRegionHandler(); + case MetaActionType::MOVECLIPREGION: + return MoveClipRegionHandler(); + case MetaActionType::LINECOLOR: + return LineColorHandler(); + case MetaActionType::FILLCOLOR: + return FillColorHandler(); + case MetaActionType::TEXTCOLOR: + return TextColorHandler(); + case MetaActionType::TEXTFILLCOLOR: + return TextFillColorHandler(); + case MetaActionType::TEXTLINECOLOR: + return TextLineColorHandler(); + case MetaActionType::OVERLINECOLOR: + return OverlineColorHandler(); + case MetaActionType::TEXTALIGN: + return TextAlignHandler(); + case MetaActionType::MAPMODE: + return MapModeHandler(); + case MetaActionType::FONT: + return FontHandler(pData); + case MetaActionType::PUSH: + return PushHandler(); + case MetaActionType::POP: + return PopHandler(); + case MetaActionType::RASTEROP: + return RasterOpHandler(); + case MetaActionType::Transparent: + return TransparentHandler(); + case MetaActionType::FLOATTRANSPARENT: + return FloatTransparentHandler(pData); + case MetaActionType::EPS: + return EPSHandler(); + case MetaActionType::REFPOINT: + return RefPointHandler(); + case MetaActionType::COMMENT: + return CommentHandler(); + case MetaActionType::LAYOUTMODE: + return LayoutModeHandler(); + case MetaActionType::TEXTLANGUAGE: + return TextLanguageHandler(); + + default: + { + VersionCompatRead aCompat(mrStream); + } + break; + } + + return pAction; +} + +void SvmReader::ReadColor(Color& rColor) +{ + sal_uInt32 nTmp(0); + mrStream.ReadUInt32(nTmp); + rColor = ::Color(ColorTransparency, nTmp); +} + +rtl::Reference SvmReader::LineColorHandler() +{ + rtl::Reference pAction(new MetaLineColorAction); + + VersionCompatRead aCompat(mrStream); + Color aColor; + ReadColor(aColor); + bool aBool(false); + mrStream.ReadCharAsBool(aBool); + + pAction->SetSetting(aBool); + pAction->SetColor(aColor); + + return pAction; +} + +rtl::Reference SvmReader::FillColorHandler() +{ + rtl::Reference pAction(new MetaFillColorAction); + + VersionCompatRead aCompat(mrStream); + + Color aColor; + ReadColor(aColor); + bool aBool(false); + mrStream.ReadCharAsBool(aBool); + + pAction->SetColor(aColor); + pAction->SetSetting(aBool); + + return pAction; +} + +rtl::Reference SvmReader::RectHandler() +{ + rtl::Reference pAction(new MetaRectAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + tools::Rectangle aRectangle; + aSerializer.readRectangle(aRectangle); + pAction->SetRect(aRectangle); + + return pAction; +} + +rtl::Reference SvmReader::PointHandler() +{ + rtl::Reference pAction(new MetaPointAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + Point aPoint; + aSerializer.readPoint(aPoint); + pAction->SetPoint(aPoint); + + return pAction; +} + +rtl::Reference SvmReader::PixelHandler() +{ + rtl::Reference pAction(new MetaPixelAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + Point aPoint; + aSerializer.readPoint(aPoint); + Color aColor; + ReadColor(aColor); + + pAction->SetPoint(aPoint); + pAction->SetColor(aColor); + + return pAction; +} + +rtl::Reference SvmReader::LineHandler() +{ + rtl::Reference pAction(new MetaLineAction); + + VersionCompatRead aCompat(mrStream); + + // Version 1 + TypeSerializer aSerializer(mrStream); + Point aPoint; + Point aEndPoint; + aSerializer.readPoint(aPoint); + aSerializer.readPoint(aEndPoint); + + pAction->SetStartPoint(aPoint); + pAction->SetEndPoint(aEndPoint); + + // Version 2 + if (aCompat.GetVersion() >= 2) + { + LineInfo aLineInfo; + ReadLineInfo(mrStream, aLineInfo); + pAction->SetLineInfo(aLineInfo); + } + + return pAction; +} + +rtl::Reference SvmReader::RoundRectHandler() +{ + rtl::Reference pAction(new MetaRoundRectAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + tools::Rectangle aRectangle; + aSerializer.readRectangle(aRectangle); + sal_uInt32 HorzRound(0); + sal_uInt32 VertRound(0); + mrStream.ReadUInt32(HorzRound).ReadUInt32(VertRound); + + pAction->SetRect(aRectangle); + pAction->SetHorzRound(HorzRound); + pAction->SetVertRound(VertRound); + + return pAction; +} + +rtl::Reference SvmReader::EllipseHandler() +{ + rtl::Reference pAction(new MetaEllipseAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + tools::Rectangle aRectangle; + aSerializer.readRectangle(aRectangle); + + pAction->SetRect(aRectangle); + + return pAction; +} + +rtl::Reference SvmReader::ArcHandler() +{ + rtl::Reference pAction(new MetaArcAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + tools::Rectangle aRectangle; + aSerializer.readRectangle(aRectangle); + Point aPoint; + aSerializer.readPoint(aPoint); + Point aEndPoint; + aSerializer.readPoint(aEndPoint); + + pAction->SetRect(aRectangle); + pAction->SetStartPoint(aPoint); + pAction->SetEndPoint(aEndPoint); + + return pAction; +} + +rtl::Reference SvmReader::PieHandler() +{ + rtl::Reference pAction(new MetaPieAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + tools::Rectangle aRectangle; + aSerializer.readRectangle(aRectangle); + Point aPoint; + aSerializer.readPoint(aPoint); + Point aEndPoint; + aSerializer.readPoint(aEndPoint); + + pAction->SetRect(aRectangle); + pAction->SetStartPoint(aPoint); + pAction->SetEndPoint(aEndPoint); + + return pAction; +} + +rtl::Reference SvmReader::ChordHandler() +{ + rtl::Reference pAction(new MetaChordAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + tools::Rectangle aRectangle; + aSerializer.readRectangle(aRectangle); + Point aPoint; + aSerializer.readPoint(aPoint); + Point aEndPoint; + aSerializer.readPoint(aEndPoint); + + pAction->SetRect(aRectangle); + pAction->SetStartPoint(aPoint); + pAction->SetEndPoint(aEndPoint); + + return pAction; +} + +rtl::Reference SvmReader::PolyLineHandler() +{ + rtl::Reference pAction(new MetaPolyLineAction); + + VersionCompatRead aCompat(mrStream); + + // Version 1 + tools::Polygon aPolygon; + ReadPolygon(mrStream, aPolygon); + + // Version 2 + if (aCompat.GetVersion() >= 2) + { + LineInfo aLineInfo; + ReadLineInfo(mrStream, aLineInfo); + pAction->SetLineInfo(aLineInfo); + } + if (aCompat.GetVersion() >= 3) + { + sal_uInt8 bHasPolyFlags(0); + mrStream.ReadUChar(bHasPolyFlags); + if (bHasPolyFlags) + aPolygon.Read(mrStream); + } + pAction->SetPolygon(aPolygon); + + return pAction; +} + +rtl::Reference SvmReader::PolygonHandler() +{ + rtl::Reference pAction(new MetaPolygonAction); + + VersionCompatRead aCompat(mrStream); + + tools::Polygon aPolygon; + ReadPolygon(mrStream, aPolygon); // Version 1 + + if (aCompat.GetVersion() >= 2) // Version 2 + { + sal_uInt8 bHasPolyFlags(0); + mrStream.ReadUChar(bHasPolyFlags); + if (bHasPolyFlags) + aPolygon.Read(mrStream); + } + + pAction->SetPolygon(aPolygon); + + return pAction; +} + +rtl::Reference SvmReader::PolyPolygonHandler() +{ + rtl::Reference pAction(new MetaPolyPolygonAction); + + VersionCompatRead aCompat(mrStream); + tools::PolyPolygon aPolyPolygon; + ReadPolyPolygon(mrStream, aPolyPolygon); // Version 1 + + if (aCompat.GetVersion() < 2) // Version 2 + { + pAction->SetPolyPolygon(aPolyPolygon); + return pAction; + } + + sal_uInt16 nNumberOfComplexPolygons(0); + mrStream.ReadUInt16(nNumberOfComplexPolygons); + const size_t nMinRecordSize = sizeof(sal_uInt16); + const size_t nMaxRecords = mrStream.remainingSize() / nMinRecordSize; + if (nNumberOfComplexPolygons > nMaxRecords) + { + SAL_WARN("vcl.gdi", "Parsing error: " << nMaxRecords << " max possible entries, but " + << nNumberOfComplexPolygons + << " claimed, truncating"); + nNumberOfComplexPolygons = nMaxRecords; + } + for (sal_uInt16 i = 0; i < nNumberOfComplexPolygons; ++i) + { + sal_uInt16 nIndex(0); + mrStream.ReadUInt16(nIndex); + tools::Polygon aPoly; + aPoly.Read(mrStream); + if (nIndex >= aPolyPolygon.Count()) + { + SAL_WARN("vcl.gdi", "svm contains polygon index " << nIndex + << " outside possible range " + << aPolyPolygon.Count()); + continue; + } + aPolyPolygon.Replace(aPoly, nIndex); + } + + pAction->SetPolyPolygon(aPolyPolygon); + + return pAction; +} + +rtl::Reference SvmReader::TextHandler(const ImplMetaReadData* pData) +{ + rtl::Reference pAction(new MetaTextAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + Point aPoint; + aSerializer.readPoint(aPoint); + OUString aStr = mrStream.ReadUniOrByteString(pData->meActualCharSet); + sal_uInt16 nTmpIndex(0); + mrStream.ReadUInt16(nTmpIndex); + sal_uInt16 nTmpLen(0); + mrStream.ReadUInt16(nTmpLen); + + pAction->SetPoint(aPoint); + + if (aCompat.GetVersion() >= 2) // Version 2 + aStr = read_uInt16_lenPrefixed_uInt16s_ToOUString(mrStream); + + if (nTmpIndex > aStr.getLength()) + { + SAL_WARN("vcl.gdi", "inconsistent offset"); + nTmpIndex = aStr.getLength(); + } + + if (nTmpLen > aStr.getLength() - nTmpIndex) + { + SAL_WARN("vcl.gdi", "inconsistent len"); + nTmpLen = aStr.getLength() - nTmpIndex; + } + + pAction->SetIndex(nTmpIndex); + pAction->SetLen(nTmpLen); + + pAction->SetText(aStr); + + return pAction; +} + +rtl::Reference SvmReader::TextArrayHandler(const ImplMetaReadData* pData) +{ + rtl::Reference pAction(new MetaTextArrayAction); + + std::vector aArray; + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + Point aPoint; + aSerializer.readPoint(aPoint); + pAction->SetPoint(aPoint); + + OUString aStr = mrStream.ReadUniOrByteString(pData->meActualCharSet); + pAction->SetText(aStr); + + sal_uInt16 nTmpIndex(0); + mrStream.ReadUInt16(nTmpIndex); + + sal_uInt16 nTmpLen(0); + mrStream.ReadUInt16(nTmpLen); + + sal_Int32 nAryLen(0); + mrStream.ReadInt32(nAryLen); + + if (nTmpLen > aStr.getLength() - nTmpIndex) + { + SAL_WARN("vcl.gdi", "inconsistent offset and len"); + pAction->SetIndex(0); + pAction->SetLen(aStr.getLength()); + return pAction; + } + + pAction->SetIndex(nTmpIndex); + pAction->SetLen(nTmpLen); + + if (nAryLen) + { + // #i9762#, #106172# Ensure that DX array is at least mnLen entries long + if (nTmpLen >= nAryLen) + { + try + { + aArray.resize(nTmpLen); + sal_Int32 i; + sal_Int32 val(0); + for (i = 0; i < nAryLen; i++) + { + mrStream.ReadInt32(val); + aArray[i] = val; + } + // #106172# setup remainder + for (; i < nTmpLen; i++) + aArray[i] = 0; + } + catch (std::bad_alloc&) + { + } + } + else + { + return pAction; + } + } + + if (aCompat.GetVersion() >= 2) // Version 2 + { + aStr = read_uInt16_lenPrefixed_uInt16s_ToOUString(mrStream); + pAction->SetText(aStr); + + if (nTmpLen > aStr.getLength() - nTmpIndex) + { + SAL_WARN("vcl.gdi", "inconsistent offset and len"); + pAction->SetIndex(0); + pAction->SetLen(aStr.getLength()); + aArray.clear(); + } + } + + if (!aArray.empty()) + pAction->SetDXArray(std::move(aArray)); + + return pAction; +} + +rtl::Reference SvmReader::StretchTextHandler(const ImplMetaReadData* pData) +{ + rtl::Reference pAction(new MetaStretchTextAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + Point aPoint; + aSerializer.readPoint(aPoint); + OUString aStr = mrStream.ReadUniOrByteString(pData->meActualCharSet); + sal_uInt32 nTmpWidth(0); + mrStream.ReadUInt32(nTmpWidth); + sal_uInt16 nTmpIndex(0); + mrStream.ReadUInt16(nTmpIndex); + sal_uInt16 nTmpLen(0); + mrStream.ReadUInt16(nTmpLen); + + pAction->SetPoint(aPoint); + pAction->SetWidth(nTmpWidth); + + if (aCompat.GetVersion() >= 2) // Version 2 + aStr = read_uInt16_lenPrefixed_uInt16s_ToOUString(mrStream); + + if (nTmpIndex > aStr.getLength()) + { + SAL_WARN("vcl.gdi", "inconsistent offset"); + nTmpIndex = aStr.getLength(); + } + + if (nTmpLen > aStr.getLength() - nTmpIndex) + { + SAL_WARN("vcl.gdi", "inconsistent len"); + nTmpLen = aStr.getLength() - nTmpIndex; + } + + pAction->SetIndex(nTmpIndex); + pAction->SetLen(nTmpLen); + + pAction->SetText(aStr); + + return pAction; +} + +rtl::Reference SvmReader::TextRectHandler(const ImplMetaReadData* pData) +{ + rtl::Reference pAction(new MetaTextRectAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + tools::Rectangle aRect; + aSerializer.readRectangle(aRect); + OUString aStr = mrStream.ReadUniOrByteString(pData->meActualCharSet); + sal_uInt16 nTmp(0); + mrStream.ReadUInt16(nTmp); + + pAction->SetRect(aRect); + pAction->SetStyle(static_cast(nTmp)); + + if (aCompat.GetVersion() >= 2) // Version 2 + aStr = read_uInt16_lenPrefixed_uInt16s_ToOUString(mrStream); + + pAction->SetText(aStr); + + return pAction; +} + +rtl::Reference SvmReader::TextLineHandler() +{ + rtl::Reference pAction(new MetaTextLineAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + Point aPos; + aSerializer.readPoint(aPos); + sal_Int32 nTempWidth(0); + mrStream.ReadInt32(nTempWidth); + + pAction->SetStartPoint(aPos); + pAction->SetWidth(nTempWidth); + + sal_uInt32 nTempStrikeout(0); + mrStream.ReadUInt32(nTempStrikeout); + sal_uInt32 nTempUnderline(0); + mrStream.ReadUInt32(nTempUnderline); + + pAction->SetStrikeout(static_cast(nTempStrikeout & SAL_MAX_ENUM)); + pAction->SetUnderline(static_cast(nTempUnderline & SAL_MAX_ENUM)); + + if (aCompat.GetVersion() >= 2) + { + sal_uInt32 nTempOverline(0); + mrStream.ReadUInt32(nTempOverline); + pAction->SetOverline(static_cast(nTempOverline & SAL_MAX_ENUM)); + } + + return pAction; +} + +rtl::Reference SvmReader::BmpHandler() +{ + rtl::Reference pAction(new MetaBmpAction); + + VersionCompatRead aCompat(mrStream); + Bitmap aBmp; + ReadDIB(aBmp, mrStream, true); + TypeSerializer aSerializer(mrStream); + Point aPoint; + aSerializer.readPoint(aPoint); + + pAction->SetBitmap(aBmp); + pAction->SetPoint(aPoint); + + return pAction; +} + +namespace +{ +void sanitizeNegativeSizeDimensions(Size& rSize) +{ + if (rSize.Width() < 0) + { + SAL_WARN("vcl.gdi", "sanitizeNegativeSizeDimensions: negative width"); + rSize.setWidth(0); + } + + if (rSize.Height() < 0) + { + SAL_WARN("vcl.gdi", "sanitizeNegativeSizeDimensions: negative height"); + rSize.setHeight(0); + } +} +} + +rtl::Reference SvmReader::BmpScaleHandler() +{ + rtl::Reference pAction(new MetaBmpScaleAction); + + VersionCompatRead aCompat(mrStream); + Bitmap aBmp; + ReadDIB(aBmp, mrStream, true); + TypeSerializer aSerializer(mrStream); + Point aPoint; + aSerializer.readPoint(aPoint); + + Size aSz; + aSerializer.readSize(aSz); + sanitizeNegativeSizeDimensions(aSz); + + pAction->SetBitmap(aBmp); + pAction->SetPoint(aPoint); + pAction->SetSize(aSz); + + return pAction; +} + +rtl::Reference SvmReader::BmpScalePartHandler() +{ + rtl::Reference pAction(new MetaBmpScalePartAction); + + VersionCompatRead aCompat(mrStream); + Bitmap aBmp; + ReadDIB(aBmp, mrStream, true); + TypeSerializer aSerializer(mrStream); + Point aDestPoint; + aSerializer.readPoint(aDestPoint); + Size aDestSize; + aSerializer.readSize(aDestSize); + Point aSrcPoint; + aSerializer.readPoint(aSrcPoint); + Size aSrcSize; + aSerializer.readSize(aSrcSize); + + pAction->SetBitmap(aBmp); + pAction->SetDestPoint(aDestPoint); + pAction->SetDestSize(aDestSize); + pAction->SetSrcPoint(aSrcPoint); + pAction->SetSrcSize(aSrcSize); + + return pAction; +} + +rtl::Reference SvmReader::BmpExHandler() +{ + rtl::Reference pAction(new MetaBmpExAction); + + VersionCompatRead aCompat(mrStream); + BitmapEx aBmpEx; + ReadDIBBitmapEx(aBmpEx, mrStream); + TypeSerializer aSerializer(mrStream); + Point aPoint; + aSerializer.readPoint(aPoint); + + pAction->SetPoint(aPoint); + pAction->SetBitmapEx(aBmpEx); + + return pAction; +} + +rtl::Reference SvmReader::BmpExScaleHandler() +{ + rtl::Reference pAction(new MetaBmpExScaleAction); + + VersionCompatRead aCompat(mrStream); + BitmapEx aBmpEx; + ReadDIBBitmapEx(aBmpEx, mrStream); + TypeSerializer aSerializer(mrStream); + Point aPoint; + aSerializer.readPoint(aPoint); + + Size aSize; + aSerializer.readSize(aSize); + sanitizeNegativeSizeDimensions(aSize); + + pAction->SetBitmapEx(aBmpEx); + pAction->SetPoint(aPoint); + pAction->SetSize(aSize); + + return pAction; +} + +rtl::Reference SvmReader::BmpExScalePartHandler() +{ + rtl::Reference pAction(new MetaBmpExScalePartAction); + + VersionCompatRead aCompat(mrStream); + BitmapEx aBmpEx; + ReadDIBBitmapEx(aBmpEx, mrStream); + TypeSerializer aSerializer(mrStream); + Point aDstPoint; + aSerializer.readPoint(aDstPoint); + Size aDstSize; + aSerializer.readSize(aDstSize); + Point aSrcPoint; + aSerializer.readPoint(aSrcPoint); + Size aSrcSize; + aSerializer.readSize(aSrcSize); + + pAction->SetBitmapEx(aBmpEx); + pAction->SetDestPoint(aDstPoint); + pAction->SetDestSize(aDstSize); + pAction->SetSrcPoint(aSrcPoint); + pAction->SetSrcSize(aSrcSize); + + return pAction; +} + +rtl::Reference SvmReader::MaskHandler() +{ + rtl::Reference pAction(new MetaMaskAction); + + VersionCompatRead aCompat(mrStream); + Bitmap aBmp; + ReadDIB(aBmp, mrStream, true); + TypeSerializer aSerializer(mrStream); + Point aPoint; + aSerializer.readPoint(aPoint); + + pAction->SetBitmap(aBmp); + pAction->SetPoint(aPoint); + + return pAction; +} + +rtl::Reference SvmReader::MaskScaleHandler() +{ + rtl::Reference pAction(new MetaMaskScaleAction); + + VersionCompatRead aCompat(mrStream); + Bitmap aBmp; + ReadDIB(aBmp, mrStream, true); + TypeSerializer aSerializer(mrStream); + Point aPoint; + aSerializer.readPoint(aPoint); + Size aSize; + aSerializer.readSize(aSize); + + pAction->SetBitmap(aBmp); + pAction->SetPoint(aPoint); + pAction->SetSize(aSize); + + return pAction; +} + +rtl::Reference SvmReader::MaskScalePartHandler() +{ + rtl::Reference pAction(new MetaMaskScalePartAction); + + VersionCompatRead aCompat(mrStream); + Bitmap aBmp; + ReadDIB(aBmp, mrStream, true); + Color aColor; + ReadColor(aColor); + TypeSerializer aSerializer(mrStream); + Point aDstPt; + aSerializer.readPoint(aDstPt); + Size aDstSz; + aSerializer.readSize(aDstSz); + Point aSrcPt; + aSerializer.readPoint(aSrcPt); + Size aSrcSz; + aSerializer.readSize(aSrcSz); + + pAction->SetBitmap(aBmp); + pAction->SetColor(aColor); + pAction->SetDestPoint(aDstPt); + pAction->SetDestSize(aDstSz); + pAction->SetSrcPoint(aSrcPt); + pAction->SetSrcSize(aSrcSz); + + return pAction; +} + +rtl::Reference SvmReader::GradientHandler() +{ + rtl::Reference pAction(new MetaGradientAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + tools::Rectangle aRect; + aSerializer.readRectangle(aRect); + Gradient aGradient; + aSerializer.readGradient(aGradient); + + pAction->SetRect(aRect); + pAction->SetGradient(aGradient); + + return pAction; +} + +rtl::Reference SvmReader::GradientExHandler() +{ + rtl::Reference pAction(new MetaGradientExAction); + + VersionCompatRead aCompat(mrStream); + tools::PolyPolygon aPolyPoly; + ReadPolyPolygon(mrStream, aPolyPoly); + TypeSerializer aSerializer(mrStream); + Gradient aGradient; + aSerializer.readGradient(aGradient); + + pAction->SetGradient(aGradient); + pAction->SetPolyPolygon(aPolyPoly); + + return pAction; +} + +rtl::Reference SvmReader::HatchHandler() +{ + rtl::Reference pAction(new MetaHatchAction); + + VersionCompatRead aCompat(mrStream); + tools::PolyPolygon aPolyPoly; + ReadPolyPolygon(mrStream, aPolyPoly); + Hatch aHatch; + ReadHatch(mrStream, aHatch); + + pAction->SetPolyPolygon(aPolyPoly); + pAction->SetHatch(aHatch); + + return pAction; +} + +rtl::Reference SvmReader::WallpaperHandler() +{ + rtl::Reference pAction(new MetaWallpaperAction); + + VersionCompatRead aCompat(mrStream); + Wallpaper aWallpaper; + ReadWallpaper(mrStream, aWallpaper); + + pAction->SetWallpaper(aWallpaper); + + return pAction; +} + +rtl::Reference SvmReader::ClipRegionHandler() +{ + rtl::Reference pAction(new MetaClipRegionAction); + + VersionCompatRead aCompat(mrStream); + vcl::Region aRegion; + ReadRegion(mrStream, aRegion); + bool aClip(false); + mrStream.ReadCharAsBool(aClip); + + pAction->SetRegion(aRegion); + pAction->SetClipping(aClip); + + return pAction; +} + +rtl::Reference SvmReader::ISectRectClipRegionHandler() +{ + rtl::Reference pAction(new MetaISectRectClipRegionAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + tools::Rectangle aRect; + aSerializer.readRectangle(aRect); + + pAction->SetRect(aRect); + + return pAction; +} + +rtl::Reference SvmReader::ISectRegionClipRegionHandler() +{ + rtl::Reference pAction(new MetaISectRegionClipRegionAction); + + VersionCompatRead aCompat(mrStream); + vcl::Region aRegion; + ReadRegion(mrStream, aRegion); + pAction->SetRegion(aRegion); + + return pAction; +} + +rtl::Reference SvmReader::MoveClipRegionHandler() +{ + rtl::Reference pAction(new MetaMoveClipRegionAction); + + VersionCompatRead aCompat(mrStream); + sal_Int32 nTmpHM(0), nTmpVM(0); + mrStream.ReadInt32(nTmpHM).ReadInt32(nTmpVM); + + pAction->SetHorzMove(nTmpHM); + pAction->SetVertMove(nTmpVM); + + return pAction; +} + +rtl::Reference SvmReader::TextColorHandler() +{ + rtl::Reference pAction(new MetaTextColorAction); + + VersionCompatRead aCompat(mrStream); + Color aColor; + ReadColor(aColor); + + pAction->SetColor(aColor); + + return pAction; +} + +rtl::Reference SvmReader::TextFillColorHandler() +{ + rtl::Reference pAction(new MetaTextFillColorAction); + + VersionCompatRead aCompat(mrStream); + Color aColor; + ReadColor(aColor); + bool bSet(false); + mrStream.ReadCharAsBool(bSet); + + pAction->SetColor(aColor); + pAction->SetSetting(bSet); + + return pAction; +} + +rtl::Reference SvmReader::TextLineColorHandler() +{ + rtl::Reference pAction(new MetaTextLineColorAction); + + VersionCompatRead aCompat(mrStream); + Color aColor; + ReadColor(aColor); + bool bSet(false); + mrStream.ReadCharAsBool(bSet); + + pAction->SetColor(aColor); + pAction->SetSetting(bSet); + + return pAction; +} + +rtl::Reference SvmReader::OverlineColorHandler() +{ + rtl::Reference pAction(new MetaOverlineColorAction); + + VersionCompatRead aCompat(mrStream); + Color aColor; + ReadColor(aColor); + bool bSet(false); + mrStream.ReadCharAsBool(bSet); + + pAction->SetColor(aColor); + pAction->SetSetting(bSet); + + return pAction; +} + +rtl::Reference SvmReader::TextAlignHandler() +{ + rtl::Reference pAction(new MetaTextAlignAction); + + VersionCompatRead aCompat(mrStream); + sal_uInt16 nTmp16(0); + mrStream.ReadUInt16(nTmp16); + + pAction->SetTextAlign(static_cast(nTmp16)); + + return pAction; +} + +rtl::Reference SvmReader::MapModeHandler() +{ + rtl::Reference pAction(new MetaMapModeAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + MapMode aMapMode; + aSerializer.readMapMode(aMapMode); + + pAction->SetMapMode(aMapMode); + + return pAction; +} + +rtl::Reference SvmReader::FontHandler(ImplMetaReadData* pData) +{ + rtl::Reference pAction(new MetaFontAction); + + VersionCompatRead aCompat(mrStream); + vcl::Font aFont; + ReadFont(mrStream, aFont); + pData->meActualCharSet = aFont.GetCharSet(); + if (pData->meActualCharSet == RTL_TEXTENCODING_DONTKNOW) + pData->meActualCharSet = osl_getThreadTextEncoding(); + + pAction->SetFont(aFont); + + return pAction; +} + +rtl::Reference SvmReader::PushHandler() +{ + rtl::Reference pAction(new MetaPushAction); + + VersionCompatRead aCompat(mrStream); + sal_uInt16 nTmp(0); + mrStream.ReadUInt16(nTmp); + + pAction->SetPushFlags(static_cast(nTmp)); + + return pAction; +} + +rtl::Reference SvmReader::PopHandler() +{ + rtl::Reference pAction(new MetaPopAction); + + VersionCompatRead aCompat(mrStream); + + return pAction; +} + +rtl::Reference SvmReader::RasterOpHandler() +{ + rtl::Reference pAction(new MetaRasterOpAction); + + sal_uInt16 nTmp16(0); + + VersionCompatRead aCompat(mrStream); + mrStream.ReadUInt16(nTmp16); + + pAction->SetRasterOp(static_cast(nTmp16)); + + return pAction; +} + +rtl::Reference SvmReader::TransparentHandler() +{ + rtl::Reference pAction(new MetaTransparentAction); + + VersionCompatRead aCompat(mrStream); + tools::PolyPolygon aPolyPoly; + ReadPolyPolygon(mrStream, aPolyPoly); + sal_uInt16 nTransPercent(0); + mrStream.ReadUInt16(nTransPercent); + + pAction->SetPolyPolygon(aPolyPoly); + pAction->SetTransparence(nTransPercent); + + return pAction; +} + +rtl::Reference SvmReader::FloatTransparentHandler(ImplMetaReadData* pData) +{ + rtl::Reference pAction(new MetaFloatTransparentAction); + + VersionCompatRead aCompat(mrStream); + GDIMetaFile aMtf; + SvmReader aReader(mrStream); + aReader.Read(aMtf, pData); + TypeSerializer aSerializer(mrStream); + Point aPoint; + aSerializer.readPoint(aPoint); + + Size aSize; + aSerializer.readSize(aSize); + sanitizeNegativeSizeDimensions(aSize); + + Gradient aGradient; + aSerializer.readGradient(aGradient); + + pAction->SetGDIMetaFile(aMtf); + pAction->SetPoint(aPoint); + pAction->SetSize(aSize); + pAction->SetGradient(aGradient); + + return pAction; +} + +rtl::Reference SvmReader::EPSHandler() +{ + rtl::Reference pAction(new MetaEPSAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + GfxLink aGfxLink; + aSerializer.readGfxLink(aGfxLink); + Point aPoint; + aSerializer.readPoint(aPoint); + Size aSize; + aSerializer.readSize(aSize); + GDIMetaFile aSubst; + Read(aSubst); + + pAction->SetLink(aGfxLink); + pAction->SetPoint(aPoint); + pAction->SetSize(aSize); + pAction->SetSubstitute(aSubst); + + return pAction; +} + +rtl::Reference SvmReader::RefPointHandler() +{ + rtl::Reference pAction(new MetaRefPointAction); + + VersionCompatRead aCompat(mrStream); + TypeSerializer aSerializer(mrStream); + + Point aRefPoint; + aSerializer.readPoint(aRefPoint); + bool bSet(false); + mrStream.ReadCharAsBool(bSet); + + pAction->SetRefPoint(aRefPoint); + pAction->SetSetting(bSet); + + return pAction; +} + +rtl::Reference SvmReader::CommentHandler() +{ + rtl::Reference pAction(new MetaCommentAction); + + VersionCompatRead aCompat(mrStream); + OString aComment; + aComment = read_uInt16_lenPrefixed_uInt8s_ToOString(mrStream); + sal_Int32 nValue(0); + sal_uInt32 nDataSize(0); + mrStream.ReadInt32(nValue).ReadUInt32(nDataSize); + + if (nDataSize > mrStream.remainingSize()) + { + SAL_WARN("vcl.gdi", "Parsing error: " << mrStream.remainingSize() << " available data, but " + << nDataSize << " claimed, truncating"); + nDataSize = mrStream.remainingSize(); + } + + SAL_INFO("vcl.gdi", "MetaCommentAction::Read " << aComment); + + std::unique_ptr pData; + pData.reset(); + + if (nDataSize) + { + pData.reset(new sal_uInt8[nDataSize]); + mrStream.ReadBytes(pData.get(), nDataSize); + } + + pAction->SetComment(aComment); + pAction->SetDataSize(nDataSize); + pAction->SetValue(nValue); + pAction->SetData(pData.get(), nDataSize); + + return pAction; +} + +rtl::Reference SvmReader::LayoutModeHandler() +{ + rtl::Reference pAction(new MetaLayoutModeAction); + + VersionCompatRead aCompat(mrStream); + sal_uInt32 tmp(0); + mrStream.ReadUInt32(tmp); + + pAction->SetLayoutMode(static_cast(tmp)); + + return pAction; +} + +rtl::Reference SvmReader::TextLanguageHandler() +{ + rtl::Reference pAction(new MetaTextLanguageAction); + + VersionCompatRead aCompat(mrStream); + sal_uInt16 nTmp = 0; + mrStream.ReadUInt16(nTmp); + + pAction->SetTextLanguage(static_cast(nTmp)); + + return pAction; +} + +rtl::Reference SvmReader::DefaultHandler() +{ + return rtl::Reference(new MetaAction); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/svm/SvmWriter.cxx b/vcl/source/filter/svm/SvmWriter.cxx new file mode 100644 index 000000000..118db1325 --- /dev/null +++ b/vcl/source/filter/svm/SvmWriter.cxx @@ -0,0 +1,1421 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include + +#include + +SvmWriter::SvmWriter(SvStream& rIStm) + : mrStream(rIStm) +{ +} + +void SvmWriter::WriteColor(::Color aColor) +{ + mrStream.WriteUInt32(static_cast(aColor)); +} + +SvStream& SvmWriter::Write(const GDIMetaFile& rMetaFile) +{ + const SvStreamCompressFlags nStmCompressMode = mrStream.GetCompressMode(); + SvStreamEndian nOldFormat = mrStream.GetEndian(); + + mrStream.SetEndian(SvStreamEndian::LITTLE); + mrStream.WriteBytes("VCLMTF", 6); + + { + VersionCompatWrite aCompat(mrStream, 1); + + mrStream.WriteUInt32(static_cast(nStmCompressMode)); + TypeSerializer aSerializer(mrStream); + aSerializer.writeMapMode(rMetaFile.GetPrefMapMode()); + aSerializer.writeSize(rMetaFile.GetPrefSize()); + mrStream.WriteUInt32(rMetaFile.GetActionSize()); + } // VersionCompatWrite dtor writes stuff into the header + + ImplMetaWriteData aWriteData; + + aWriteData.meActualCharSet = mrStream.GetStreamCharSet(); + + MetaAction* pAct = const_cast(rMetaFile).FirstAction(); + while (pAct) + { + MetaActionHandler(pAct, &aWriteData); + pAct = const_cast(rMetaFile).NextAction(); + } + + mrStream.SetEndian(nOldFormat); + + return mrStream; +} + +BitmapChecksum SvmWriter::GetChecksum(const GDIMetaFile& rMetaFile) +{ + SvMemoryStream aMemStm(65535, 65535); + ImplMetaWriteData aWriteData; + SVBT16 aBT16; + SVBT32 aBT32; + BitmapChecksumOctetArray aBCOA; + BitmapChecksum nCrc = 0; + + aWriteData.meActualCharSet = aMemStm.GetStreamCharSet(); + + for (size_t i = 0, nObjCount = rMetaFile.GetActionSize(); i < nObjCount; i++) + { + MetaAction* pAction = rMetaFile.GetAction(i); + + switch (pAction->GetType()) + { + case MetaActionType::BMP: + { + MetaBmpAction* pAct = static_cast(pAction); + + ShortToSVBT16(static_cast(pAct->GetType()), aBT16); + nCrc = vcl_get_checksum(nCrc, aBT16, 2); + + BCToBCOA(pAct->GetBitmap().GetChecksum(), aBCOA); + nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE); + + Int32ToSVBT32(pAct->GetPoint().X(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetPoint().Y(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + } + break; + + case MetaActionType::BMPSCALE: + { + MetaBmpScaleAction* pAct = static_cast(pAction); + + ShortToSVBT16(static_cast(pAct->GetType()), aBT16); + nCrc = vcl_get_checksum(nCrc, aBT16, 2); + + BCToBCOA(pAct->GetBitmap().GetChecksum(), aBCOA); + nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE); + + Int32ToSVBT32(pAct->GetPoint().X(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetPoint().Y(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSize().Width(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSize().Height(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + } + break; + + case MetaActionType::BMPSCALEPART: + { + MetaBmpScalePartAction* pAct = static_cast(pAction); + + ShortToSVBT16(static_cast(pAct->GetType()), aBT16); + nCrc = vcl_get_checksum(nCrc, aBT16, 2); + + BCToBCOA(pAct->GetBitmap().GetChecksum(), aBCOA); + nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE); + + Int32ToSVBT32(pAct->GetDestPoint().X(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetDestPoint().Y(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetDestSize().Width(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetDestSize().Height(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSrcPoint().X(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSrcPoint().Y(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSrcSize().Width(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSrcSize().Height(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + } + break; + + case MetaActionType::BMPEX: + { + MetaBmpExAction* pAct = static_cast(pAction); + + ShortToSVBT16(static_cast(pAct->GetType()), aBT16); + nCrc = vcl_get_checksum(nCrc, aBT16, 2); + + BCToBCOA(pAct->GetBitmapEx().GetChecksum(), aBCOA); + nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE); + + Int32ToSVBT32(pAct->GetPoint().X(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetPoint().Y(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + } + break; + + case MetaActionType::BMPEXSCALE: + { + MetaBmpExScaleAction* pAct = static_cast(pAction); + + ShortToSVBT16(static_cast(pAct->GetType()), aBT16); + nCrc = vcl_get_checksum(nCrc, aBT16, 2); + + BCToBCOA(pAct->GetBitmapEx().GetChecksum(), aBCOA); + nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE); + + Int32ToSVBT32(pAct->GetPoint().X(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetPoint().Y(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSize().Width(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSize().Height(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + } + break; + + case MetaActionType::BMPEXSCALEPART: + { + MetaBmpExScalePartAction* pAct = static_cast(pAction); + + ShortToSVBT16(static_cast(pAct->GetType()), aBT16); + nCrc = vcl_get_checksum(nCrc, aBT16, 2); + + BCToBCOA(pAct->GetBitmapEx().GetChecksum(), aBCOA); + nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE); + + Int32ToSVBT32(pAct->GetDestPoint().X(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetDestPoint().Y(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetDestSize().Width(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetDestSize().Height(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSrcPoint().X(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSrcPoint().Y(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSrcSize().Width(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSrcSize().Height(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + } + break; + + case MetaActionType::MASK: + { + MetaMaskAction* pAct = static_cast(pAction); + + ShortToSVBT16(static_cast(pAct->GetType()), aBT16); + nCrc = vcl_get_checksum(nCrc, aBT16, 2); + + BCToBCOA(pAct->GetBitmap().GetChecksum(), aBCOA); + nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE); + + UInt32ToSVBT32(sal_uInt32(pAct->GetColor()), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetPoint().X(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetPoint().Y(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + } + break; + + case MetaActionType::MASKSCALE: + { + MetaMaskScaleAction* pAct = static_cast(pAction); + + ShortToSVBT16(static_cast(pAct->GetType()), aBT16); + nCrc = vcl_get_checksum(nCrc, aBT16, 2); + + BCToBCOA(pAct->GetBitmap().GetChecksum(), aBCOA); + nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE); + + UInt32ToSVBT32(sal_uInt32(pAct->GetColor()), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetPoint().X(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetPoint().Y(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSize().Width(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSize().Height(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + } + break; + + case MetaActionType::MASKSCALEPART: + { + MetaMaskScalePartAction* pAct = static_cast(pAction); + + ShortToSVBT16(static_cast(pAct->GetType()), aBT16); + nCrc = vcl_get_checksum(nCrc, aBT16, 2); + + BCToBCOA(pAct->GetBitmap().GetChecksum(), aBCOA); + nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE); + + UInt32ToSVBT32(sal_uInt32(pAct->GetColor()), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetDestPoint().X(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetDestPoint().Y(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetDestSize().Width(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetDestSize().Height(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSrcPoint().X(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSrcPoint().Y(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSrcSize().Width(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(pAct->GetSrcSize().Height(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + } + break; + + case MetaActionType::EPS: + { + MetaEPSAction* pAct = static_cast(pAction); + nCrc = vcl_get_checksum(nCrc, pAct->GetLink().GetData(), + pAct->GetLink().GetDataSize()); + } + break; + + case MetaActionType::CLIPREGION: + { + MetaClipRegionAction& rAct = static_cast(*pAction); + const vcl::Region& rRegion = rAct.GetRegion(); + + if (rRegion.HasPolyPolygonOrB2DPolyPolygon()) + { + // It has shown that this is a possible bottleneck for checksum calculation. + // In worst case a very expensive RegionHandle representation gets created. + // In this case it's cheaper to use the PolyPolygon + const basegfx::B2DPolyPolygon aPolyPolygon(rRegion.GetAsB2DPolyPolygon()); + SVBT64 aSVBT64; + + for (auto const& rPolygon : aPolyPolygon) + { + const sal_uInt32 nPointCount(rPolygon.count()); + const bool bControl(rPolygon.areControlPointsUsed()); + + for (sal_uInt32 b(0); b < nPointCount; b++) + { + const basegfx::B2DPoint aPoint(rPolygon.getB2DPoint(b)); + + DoubleToSVBT64(aPoint.getX(), aSVBT64); + nCrc = vcl_get_checksum(nCrc, aSVBT64, 8); + DoubleToSVBT64(aPoint.getY(), aSVBT64); + nCrc = vcl_get_checksum(nCrc, aSVBT64, 8); + + if (bControl) + { + if (rPolygon.isPrevControlPointUsed(b)) + { + const basegfx::B2DPoint aCtrl(rPolygon.getPrevControlPoint(b)); + + DoubleToSVBT64(aCtrl.getX(), aSVBT64); + nCrc = vcl_get_checksum(nCrc, aSVBT64, 8); + DoubleToSVBT64(aCtrl.getY(), aSVBT64); + nCrc = vcl_get_checksum(nCrc, aSVBT64, 8); + } + + if (rPolygon.isNextControlPointUsed(b)) + { + const basegfx::B2DPoint aCtrl(rPolygon.getNextControlPoint(b)); + + DoubleToSVBT64(aCtrl.getX(), aSVBT64); + nCrc = vcl_get_checksum(nCrc, aSVBT64, 8); + DoubleToSVBT64(aCtrl.getY(), aSVBT64); + nCrc = vcl_get_checksum(nCrc, aSVBT64, 8); + } + } + } + } + + sal_uInt8 tmp = static_cast(rAct.IsClipping()); + nCrc = vcl_get_checksum(nCrc, &tmp, 1); + } + else + { + SvmWriter aWriter(aMemStm); + aWriter.MetaActionHandler(pAction, &aWriteData); + nCrc = vcl_get_checksum(nCrc, aMemStm.GetData(), aMemStm.Tell()); + aMemStm.Seek(0); + } + } + break; + + default: + { + SvmWriter aWriter(aMemStm); + aWriter.MetaActionHandler(pAction, &aWriteData); + nCrc = vcl_get_checksum(nCrc, aMemStm.GetData(), aMemStm.Tell()); + aMemStm.Seek(0); + } + break; + } + } + + return nCrc; +} + +void SvmWriter::MetaActionHandler(MetaAction* pAction, ImplMetaWriteData* pData) +{ + MetaActionType nType = pAction->GetType(); + + switch (nType) + { + case MetaActionType::NONE: + { + ActionHandler(pAction); + } + break; + + case MetaActionType::PIXEL: + { + auto* pMetaAction = static_cast(pAction); + PixelHandler(pMetaAction); + } + break; + + case MetaActionType::POINT: + { + auto pMetaAction = static_cast(pAction); + PointHandler(pMetaAction); + } + break; + + case MetaActionType::LINE: + { + auto* pMetaAction = static_cast(pAction); + LineHandler(pMetaAction); + } + break; + + case MetaActionType::RECT: + { + auto* pMetaAction = static_cast(pAction); + RectHandler(pMetaAction); + } + break; + + case MetaActionType::ROUNDRECT: + { + auto* pMetaAction = static_cast(pAction); + RoundRectHandler(pMetaAction); + } + break; + + case MetaActionType::ELLIPSE: + { + auto* pMetaAction = static_cast(pAction); + EllipseHandler(pMetaAction); + } + break; + + case MetaActionType::ARC: + { + auto* pMetaAction = static_cast(pAction); + ArcHandler(pMetaAction); + } + break; + + case MetaActionType::PIE: + { + auto* pMetaAction = static_cast(pAction); + PieHandler(pMetaAction); + } + break; + + case MetaActionType::CHORD: + { + auto* pMetaAction = static_cast(pAction); + ChordHandler(pMetaAction); + } + break; + + case MetaActionType::POLYLINE: + { + auto* pMetaAction = static_cast(pAction); + PolyLineHandler(pMetaAction); + } + break; + + case MetaActionType::POLYGON: + { + auto* pMetaAction = static_cast(pAction); + PolygonHandler(pMetaAction); + } + break; + + case MetaActionType::POLYPOLYGON: + { + auto* pMetaAction = static_cast(pAction); + PolyPolygonHandler(pMetaAction); + } + break; + + case MetaActionType::TEXT: + { + auto* pMetaAction = static_cast(pAction); + TextHandler(pMetaAction, pData); + } + break; + + case MetaActionType::TEXTARRAY: + { + auto* pMetaAction = static_cast(pAction); + TextArrayHandler(pMetaAction, pData); + } + break; + + case MetaActionType::STRETCHTEXT: + { + auto* pMetaAction = static_cast(pAction); + StretchTextHandler(pMetaAction, pData); + } + break; + + case MetaActionType::TEXTRECT: + { + auto* pMetaAction = static_cast(pAction); + TextRectHandler(pMetaAction, pData); + } + break; + + case MetaActionType::TEXTLINE: + { + auto* pMetaAction = static_cast(pAction); + TextLineHandler(pMetaAction); + } + break; + + case MetaActionType::BMP: + { + auto* pMetaAction = static_cast(pAction); + BmpHandler(pMetaAction); + } + break; + + case MetaActionType::BMPSCALE: + { + auto* pMetaAction = static_cast(pAction); + BmpScaleHandler(pMetaAction); + } + break; + + case MetaActionType::BMPSCALEPART: + { + auto* pMetaAction = static_cast(pAction); + BmpScalePartHandler(pMetaAction); + } + break; + + case MetaActionType::BMPEX: + { + auto* pMetaAction = static_cast(pAction); + BmpExHandler(pMetaAction); + } + break; + + case MetaActionType::BMPEXSCALE: + { + auto* pMetaAction = static_cast(pAction); + BmpExScaleHandler(pMetaAction); + } + break; + + case MetaActionType::BMPEXSCALEPART: + { + auto* pMetaAction = static_cast(pAction); + BmpExScalePartHandler(pMetaAction); + } + break; + + case MetaActionType::MASK: + { + auto* pMetaAction = static_cast(pAction); + MaskHandler(pMetaAction); + } + break; + + case MetaActionType::MASKSCALE: + { + auto* pMetaAction = static_cast(pAction); + MaskScaleHandler(pMetaAction); + } + break; + + case MetaActionType::MASKSCALEPART: + { + auto* pMetaAction = static_cast(pAction); + MaskScalePartHandler(pMetaAction); + } + break; + + case MetaActionType::GRADIENT: + { + auto* pMetaAction = static_cast(pAction); + GradientHandler(pMetaAction); + } + break; + + case MetaActionType::GRADIENTEX: + { + auto* pMetaAction = static_cast(pAction); + GradientExHandler(pMetaAction); + } + break; + + case MetaActionType::HATCH: + { + auto* pMetaAction = static_cast(pAction); + HatchHandler(pMetaAction); + } + break; + + case MetaActionType::WALLPAPER: + { + auto* pMetaAction = static_cast(pAction); + WallpaperHandler(pMetaAction); + } + break; + + case MetaActionType::CLIPREGION: + { + auto* pMetaAction = static_cast(pAction); + ClipRegionHandler(pMetaAction); + } + break; + + case MetaActionType::ISECTRECTCLIPREGION: + { + auto* pMetaAction = static_cast(pAction); + ISectRectClipRegionHandler(pMetaAction); + } + break; + + case MetaActionType::ISECTREGIONCLIPREGION: + { + auto* pMetaAction = static_cast(pAction); + ISectRegionClipRegionHandler(pMetaAction); + } + break; + + case MetaActionType::MOVECLIPREGION: + { + auto* pMetaAction = static_cast(pAction); + MoveClipRegionHandler(pMetaAction); + } + break; + + case MetaActionType::LINECOLOR: + { + auto* pMetaAction = static_cast(pAction); + LineColorHandler(pMetaAction); + } + break; + + case MetaActionType::FILLCOLOR: + { + auto* pMetaAction = static_cast(pAction); + FillColorHandler(pMetaAction); + } + break; + + case MetaActionType::TEXTCOLOR: + { + auto* pMetaAction = static_cast(pAction); + TextColorHandler(pMetaAction); + } + break; + + case MetaActionType::TEXTFILLCOLOR: + { + auto* pMetaAction = static_cast(pAction); + TextFillColorHandler(pMetaAction); + } + break; + + case MetaActionType::TEXTLINECOLOR: + { + auto* pMetaAction = static_cast(pAction); + TextLineColorHandler(pMetaAction); + } + break; + + case MetaActionType::OVERLINECOLOR: + { + auto* pMetaAction = static_cast(pAction); + OverlineColorHandler(pMetaAction); + } + break; + + case MetaActionType::TEXTALIGN: + { + auto* pMetaAction = static_cast(pAction); + TextAlignHandler(pMetaAction); + } + break; + + case MetaActionType::MAPMODE: + { + auto* pMetaAction = static_cast(pAction); + MapModeHandler(pMetaAction); + } + break; + + case MetaActionType::FONT: + { + auto* pMetaAction = static_cast(pAction); + FontHandler(pMetaAction, pData); + } + break; + + case MetaActionType::PUSH: + { + auto* pMetaAction = static_cast(pAction); + PushHandler(pMetaAction); + } + break; + + case MetaActionType::POP: + { + auto* pMetaAction = static_cast(pAction); + PopHandler(pMetaAction); + } + break; + + case MetaActionType::RASTEROP: + { + auto* pMetaAction = static_cast(pAction); + RasterOpHandler(pMetaAction); + } + break; + + case MetaActionType::Transparent: + { + auto* pMetaAction = static_cast(pAction); + TransparentHandler(pMetaAction); + } + break; + + case MetaActionType::FLOATTRANSPARENT: + { + auto* pMetaAction = static_cast(pAction); + FloatTransparentHandler(pMetaAction); + } + break; + + case MetaActionType::EPS: + { + auto* pMetaAction = static_cast(pAction); + EPSHandler(pMetaAction); + } + break; + + case MetaActionType::REFPOINT: + { + auto* pMetaAction = static_cast(pAction); + RefPointHandler(pMetaAction); + } + break; + + case MetaActionType::COMMENT: + { + auto* pMetaAction = static_cast(pAction); + CommentHandler(pMetaAction); + } + break; + + case MetaActionType::LAYOUTMODE: + { + auto* pMetaAction = static_cast(pAction); + LayoutModeHandler(pMetaAction); + } + break; + + case MetaActionType::TEXTLANGUAGE: + { + auto* pMetaAction = static_cast(pAction); + TextLanguageHandler(pMetaAction); + } + break; + } +} + +void SvmWriter::ActionHandler(const MetaAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); +} + +void SvmWriter::PixelHandler(const MetaPixelAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetPoint()); + WriteColor(pAction->GetColor()); +} + +void SvmWriter::PointHandler(const MetaPointAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetPoint()); +} + +void SvmWriter::LineHandler(const MetaLineAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 2); + + // Version 1 + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetStartPoint()); + aSerializer.writePoint(pAction->GetEndPoint()); + // Version 2 + WriteLineInfo(mrStream, pAction->GetLineInfo()); +} + +void SvmWriter::RectHandler(const MetaRectAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 1); + TypeSerializer aSerializer(mrStream); + aSerializer.writeRectangle(pAction->GetRect()); +} + +void SvmWriter::RoundRectHandler(const MetaRoundRectAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 1); + TypeSerializer aSerializer(mrStream); + aSerializer.writeRectangle(pAction->GetRect()); + mrStream.WriteUInt32(pAction->GetHorzRound()).WriteUInt32(pAction->GetVertRound()); +} + +void SvmWriter::EllipseHandler(const MetaEllipseAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 1); + TypeSerializer aSerializer(mrStream); + aSerializer.writeRectangle(pAction->GetRect()); +} + +void SvmWriter::ArcHandler(const MetaArcAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 1); + TypeSerializer aSerializer(mrStream); + aSerializer.writeRectangle(pAction->GetRect()); + aSerializer.writePoint(pAction->GetStartPoint()); + aSerializer.writePoint(pAction->GetEndPoint()); +} + +void SvmWriter::PieHandler(const MetaPieAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 1); + TypeSerializer aSerializer(mrStream); + aSerializer.writeRectangle(pAction->GetRect()); + aSerializer.writePoint(pAction->GetStartPoint()); + aSerializer.writePoint(pAction->GetEndPoint()); +} + +void SvmWriter::ChordHandler(const MetaChordAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 1); + TypeSerializer aSerializer(mrStream); + aSerializer.writeRectangle(pAction->GetRect()); + aSerializer.writePoint(pAction->GetStartPoint()); + aSerializer.writePoint(pAction->GetEndPoint()); +} + +void SvmWriter::PolyLineHandler(const MetaPolyLineAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 3); + + tools::Polygon aSimplePoly; + pAction->GetPolygon().AdaptiveSubdivide(aSimplePoly); + + WritePolygon(mrStream, aSimplePoly); // Version 1 + WriteLineInfo(mrStream, pAction->GetLineInfo()); // Version 2 + + bool bHasPolyFlags = pAction->GetPolygon().HasFlags(); // Version 3 + mrStream.WriteBool(bHasPolyFlags); + if (bHasPolyFlags) + pAction->GetPolygon().Write(mrStream); +} + +void SvmWriter::PolygonHandler(const MetaPolygonAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 2); + + tools::Polygon aSimplePoly; // Version 1 + pAction->GetPolygon().AdaptiveSubdivide(aSimplePoly); + WritePolygon(mrStream, aSimplePoly); + + bool bHasPolyFlags = pAction->GetPolygon().HasFlags(); // Version 2 + mrStream.WriteBool(bHasPolyFlags); + if (bHasPolyFlags) + pAction->GetPolygon().Write(mrStream); +} + +void SvmWriter::PolyPolygonHandler(const MetaPolyPolygonAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 2); + + sal_uInt16 nNumberOfComplexPolygons = 0; + sal_uInt16 i, nPolyCount = pAction->GetPolyPolygon().Count(); + + tools::Polygon aSimplePoly; // Version 1 + mrStream.WriteUInt16(nPolyCount); + for (i = 0; i < nPolyCount; i++) + { + const tools::Polygon& rPoly = pAction->GetPolyPolygon().GetObject(i); + if (rPoly.HasFlags()) + nNumberOfComplexPolygons++; + rPoly.AdaptiveSubdivide(aSimplePoly); + WritePolygon(mrStream, aSimplePoly); + } + + mrStream.WriteUInt16(nNumberOfComplexPolygons); // Version 2 + for (i = 0; nNumberOfComplexPolygons && (i < nPolyCount); i++) + { + const tools::Polygon& rPoly = pAction->GetPolyPolygon().GetObject(i); + if (rPoly.HasFlags()) + { + mrStream.WriteUInt16(i); + rPoly.Write(mrStream); + + nNumberOfComplexPolygons--; + } + } +} + +void SvmWriter::TextHandler(const MetaTextAction* pAction, const ImplMetaWriteData* pData) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 2); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetPoint()); + mrStream.WriteUniOrByteString(pAction->GetText(), pData->meActualCharSet); + mrStream.WriteUInt16(pAction->GetIndex()); + mrStream.WriteUInt16(pAction->GetLen()); + + write_uInt16_lenPrefixed_uInt16s_FromOUString(mrStream, pAction->GetText()); // version 2 +} + +void SvmWriter::TextArrayHandler(const MetaTextArrayAction* pAction, const ImplMetaWriteData* pData) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + const std::vector& rDXArray = pAction->GetDXArray(); + + const sal_Int32 nAryLen = !rDXArray.empty() ? pAction->GetLen() : 0; + + VersionCompatWrite aCompat(mrStream, 2); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetPoint()); + mrStream.WriteUniOrByteString(pAction->GetText(), pData->meActualCharSet); + mrStream.WriteUInt16(pAction->GetIndex()); + mrStream.WriteUInt16(pAction->GetLen()); + mrStream.WriteInt32(nAryLen); + + for (sal_Int32 i = 0; i < nAryLen; ++i) + mrStream.WriteInt32(rDXArray[i]); + + write_uInt16_lenPrefixed_uInt16s_FromOUString(mrStream, pAction->GetText()); // version 2 +} + +void SvmWriter::StretchTextHandler(const MetaStretchTextAction* pAction, + const ImplMetaWriteData* pData) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 2); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetPoint()); + mrStream.WriteUniOrByteString(pAction->GetText(), pData->meActualCharSet); + mrStream.WriteUInt32(pAction->GetWidth()); + mrStream.WriteUInt16(pAction->GetIndex()); + mrStream.WriteUInt16(pAction->GetLen()); + + write_uInt16_lenPrefixed_uInt16s_FromOUString(mrStream, pAction->GetText()); // version 2 +} + +void SvmWriter::TextRectHandler(const MetaTextRectAction* pAction, const ImplMetaWriteData* pData) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 2); + TypeSerializer aSerializer(mrStream); + aSerializer.writeRectangle(pAction->GetRect()); + mrStream.WriteUniOrByteString(pAction->GetText(), pData->meActualCharSet); + mrStream.WriteUInt16(static_cast(pAction->GetStyle())); + + write_uInt16_lenPrefixed_uInt16s_FromOUString(mrStream, pAction->GetText()); // version 2 +} + +void SvmWriter::TextLineHandler(const MetaTextLineAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + + VersionCompatWrite aCompat(mrStream, 2); + + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetStartPoint()); + + mrStream.WriteInt32(pAction->GetWidth()); + mrStream.WriteUInt32(pAction->GetStrikeout()); + mrStream.WriteUInt32(pAction->GetUnderline()); + // new in version 2 + mrStream.WriteUInt32(pAction->GetOverline()); +} + +void SvmWriter::BmpHandler(const MetaBmpAction* pAction) +{ + if (!pAction->GetBitmap().IsEmpty()) + { + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteDIB(pAction->GetBitmap(), mrStream, false, true); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetPoint()); + } +} + +void SvmWriter::BmpScaleHandler(const MetaBmpScaleAction* pAction) +{ + if (!pAction->GetBitmap().IsEmpty()) + { + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteDIB(pAction->GetBitmap(), mrStream, false, true); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetPoint()); + aSerializer.writeSize(pAction->GetSize()); + } +} + +void SvmWriter::BmpScalePartHandler(const MetaBmpScalePartAction* pAction) +{ + if (!pAction->GetBitmap().IsEmpty()) + { + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteDIB(pAction->GetBitmap(), mrStream, false, true); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetDestPoint()); + aSerializer.writeSize(pAction->GetDestSize()); + aSerializer.writePoint(pAction->GetSrcPoint()); + aSerializer.writeSize(pAction->GetSrcSize()); + } +} + +void SvmWriter::BmpExHandler(const MetaBmpExAction* pAction) +{ + if (!pAction->GetBitmapEx().GetBitmap().IsEmpty()) + { + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteDIBBitmapEx(pAction->GetBitmapEx(), mrStream); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetPoint()); + } +} + +void SvmWriter::BmpExScaleHandler(const MetaBmpExScaleAction* pAction) +{ + if (!pAction->GetBitmapEx().GetBitmap().IsEmpty()) + { + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteDIBBitmapEx(pAction->GetBitmapEx(), mrStream); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetPoint()); + aSerializer.writeSize(pAction->GetSize()); + } +} + +void SvmWriter::BmpExScalePartHandler(const MetaBmpExScalePartAction* pAction) +{ + if (!pAction->GetBitmapEx().GetBitmap().IsEmpty()) + { + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteDIBBitmapEx(pAction->GetBitmapEx(), mrStream); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetDestPoint()); + aSerializer.writeSize(pAction->GetDestSize()); + aSerializer.writePoint(pAction->GetSrcPoint()); + aSerializer.writeSize(pAction->GetSrcSize()); + } +} + +void SvmWriter::MaskHandler(const MetaMaskAction* pAction) +{ + if (!pAction->GetBitmap().IsEmpty()) + { + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteDIB(pAction->GetBitmap(), mrStream, false, true); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetPoint()); + } +} + +void SvmWriter::MaskScaleHandler(const MetaMaskScaleAction* pAction) +{ + if (!pAction->GetBitmap().IsEmpty()) + { + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteDIB(pAction->GetBitmap(), mrStream, false, true); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetPoint()); + aSerializer.writeSize(pAction->GetSize()); + } +} + +void SvmWriter::MaskScalePartHandler(const MetaMaskScalePartAction* pAction) +{ + if (!pAction->GetBitmap().IsEmpty()) + { + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteDIB(pAction->GetBitmap(), mrStream, false, true); + WriteColor(pAction->GetColor()); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetDestPoint()); + aSerializer.writeSize(pAction->GetDestSize()); + aSerializer.writePoint(pAction->GetSrcPoint()); + aSerializer.writeSize(pAction->GetSrcSize()); + } +} + +void SvmWriter::GradientHandler(const MetaGradientAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + TypeSerializer aSerializer(mrStream); + aSerializer.writeRectangle(pAction->GetRect()); + aSerializer.writeGradient(pAction->GetGradient()); +} + +void SvmWriter::GradientExHandler(const MetaGradientExAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + + // #i105373# see comment at MetaTransparentAction::Write + tools::PolyPolygon aNoCurvePolyPolygon; + pAction->GetPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon); + + WritePolyPolygon(mrStream, aNoCurvePolyPolygon); + TypeSerializer aSerializer(mrStream); + aSerializer.writeGradient(pAction->GetGradient()); +} + +void SvmWriter::HatchHandler(const MetaHatchAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + + // #i105373# see comment at MetaTransparentAction::Write + tools::PolyPolygon aNoCurvePolyPolygon; + pAction->GetPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon); + + WritePolyPolygon(mrStream, aNoCurvePolyPolygon); + WriteHatch(mrStream, pAction->GetHatch()); +} + +void SvmWriter::WallpaperHandler(const MetaWallpaperAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + + WriteWallpaper(mrStream, pAction->GetWallpaper()); +} + +void SvmWriter::ClipRegionHandler(const MetaClipRegionAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteRegion(mrStream, pAction->GetRegion()); + mrStream.WriteBool(pAction->IsClipping()); +} + +void SvmWriter::ISectRectClipRegionHandler(const MetaISectRectClipRegionAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + TypeSerializer aSerializer(mrStream); + aSerializer.writeRectangle(pAction->GetRect()); +} + +void SvmWriter::ISectRegionClipRegionHandler(const MetaISectRegionClipRegionAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteRegion(mrStream, pAction->GetRegion()); +} + +void SvmWriter::MoveClipRegionHandler(const MetaMoveClipRegionAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + mrStream.WriteInt32(pAction->GetHorzMove()).WriteInt32(pAction->GetVertMove()); +} + +void SvmWriter::LineColorHandler(const MetaLineColorAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteColor(pAction->GetColor()); + mrStream.WriteBool(pAction->IsSetting()); +} + +void SvmWriter::FillColorHandler(const MetaFillColorAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteColor(pAction->GetColor()); + mrStream.WriteBool(pAction->IsSetting()); +} + +void SvmWriter::TextColorHandler(const MetaTextColorAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteColor(pAction->GetColor()); +} + +void SvmWriter::TextFillColorHandler(const MetaTextFillColorAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteColor(pAction->GetColor()); + mrStream.WriteBool(pAction->IsSetting()); +} + +void SvmWriter::TextLineColorHandler(const MetaTextLineColorAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteColor(pAction->GetColor()); + mrStream.WriteBool(pAction->IsSetting()); +} + +void SvmWriter::OverlineColorHandler(const MetaOverlineColorAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteColor(pAction->GetColor()); + mrStream.WriteBool(pAction->IsSetting()); +} + +void SvmWriter::TextAlignHandler(const MetaTextAlignAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + mrStream.WriteUInt16(static_cast(pAction->GetTextAlign())); +} + +void SvmWriter::MapModeHandler(const MetaMapModeAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + TypeSerializer aSerializer(mrStream); + aSerializer.writeMapMode(pAction->GetMapMode()); +} + +void SvmWriter::FontHandler(const MetaFontAction* pAction, ImplMetaWriteData* pData) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + WriteFont(mrStream, pAction->GetFont()); + pData->meActualCharSet = pAction->GetFont().GetCharSet(); + if (pData->meActualCharSet == RTL_TEXTENCODING_DONTKNOW) + pData->meActualCharSet = osl_getThreadTextEncoding(); +} + +void SvmWriter::PushHandler(const MetaPushAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + mrStream.WriteUInt16(static_cast(pAction->GetFlags())); +} + +void SvmWriter::PopHandler(const MetaPopAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); +} + +void SvmWriter::RasterOpHandler(const MetaRasterOpAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + mrStream.WriteUInt16(static_cast(pAction->GetRasterOp())); +} + +void SvmWriter::TransparentHandler(const MetaTransparentAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + + // #i105373# The tools::PolyPolygon in this action may be a curve; this + // was ignored until now what is an error. To make older office + // versions work with MetaFiles, i opt for applying AdaptiveSubdivide + // to the PolyPolygon. + // The alternative would be to really write the curve information + // like in MetaPolyPolygonAction::Write (where someone extended it + // correctly, but not here :-( ). + // The golden solution would be to combine both, but i think it's + // not necessary; a good subdivision will be sufficient. + tools::PolyPolygon aNoCurvePolyPolygon; + pAction->GetPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon); + + WritePolyPolygon(mrStream, aNoCurvePolyPolygon); + mrStream.WriteUInt16(pAction->GetTransparence()); +} + +void SvmWriter::FloatTransparentHandler(const MetaFloatTransparentAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + + SvmWriter aWriter(mrStream); + GDIMetaFile aMtf = pAction->GetGDIMetaFile(); + aWriter.Write(aMtf); + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetPoint()); + aSerializer.writeSize(pAction->GetSize()); + aSerializer.writeGradient(pAction->GetGradient()); +} + +void SvmWriter::EPSHandler(const MetaEPSAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + + TypeSerializer aSerializer(mrStream); + aSerializer.writeGfxLink(pAction->GetLink()); + aSerializer.writePoint(pAction->GetPoint()); + aSerializer.writeSize(pAction->GetSize()); + + SvmWriter aWriter(mrStream); + GDIMetaFile aMtf = pAction->GetSubstitute(); + aWriter.Write(aMtf); +} + +void SvmWriter::RefPointHandler(const MetaRefPointAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + + TypeSerializer aSerializer(mrStream); + aSerializer.writePoint(pAction->GetRefPoint()); + mrStream.WriteBool(pAction->IsSetting()); +} + +void SvmWriter::CommentHandler(const MetaCommentAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + write_uInt16_lenPrefixed_uInt8s_FromOString(mrStream, pAction->GetComment()); + mrStream.WriteInt32(pAction->GetValue()).WriteUInt32(pAction->GetDataSize()); + + if (pAction->GetDataSize()) + mrStream.WriteBytes(pAction->GetData(), pAction->GetDataSize()); +} + +void SvmWriter::LayoutModeHandler(const MetaLayoutModeAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + mrStream.WriteUInt32(static_cast(pAction->GetLayoutMode())); +} + +void SvmWriter::TextLanguageHandler(const MetaTextLanguageAction* pAction) +{ + mrStream.WriteUInt16(static_cast(pAction->GetType())); + VersionCompatWrite aCompat(mrStream, 1); + mrStream.WriteUInt16(static_cast(pAction->GetTextLanguage())); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3