summaryrefslogtreecommitdiff
path: root/svtools
diff options
context:
space:
mode:
authorsj <sj@openoffice.org>2009-12-03 16:31:03 +0100
committersj <sj@openoffice.org>2009-12-03 16:31:03 +0100
commit11c7cf17c5b96e2201cfaf43f5b4aa6cf2c34906 (patch)
treedc938f48be13dceb985d5946203cc54f202bd1c1 /svtools
parentc0f197f920974f3fdaf8278dad16dc5ecb994d52 (diff)
impress181: #i107292#: Applied patch, wmf filter is now supporting embedded EMF data from the META_ESCAPE action.
Diffstat (limited to 'svtools')
-rw-r--r--svtools/source/filter.vcl/wmf/winmtf.cxx5
-rw-r--r--svtools/source/filter.vcl/wmf/winmtf.hxx15
-rw-r--r--svtools/source/filter.vcl/wmf/winwmf.cxx216
-rw-r--r--svtools/source/filter.vcl/wmf/wmfwr.cxx80
-rw-r--r--svtools/source/filter.vcl/wmf/wmfwr.hxx9
5 files changed, 264 insertions, 61 deletions
diff --git a/svtools/source/filter.vcl/wmf/winmtf.cxx b/svtools/source/filter.vcl/wmf/winmtf.cxx
index 6f1caae18750..3db3e6957e41 100644
--- a/svtools/source/filter.vcl/wmf/winmtf.cxx
+++ b/svtools/source/filter.vcl/wmf/winmtf.cxx
@@ -2195,3 +2195,8 @@ void WinMtfOutput::Pop()
}
}
+void WinMtfOutput::AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile )
+{
+ rGDIMetaFile.Play( *mpGDIMetaFile, 0xFFFFFFFF );
+}
+
diff --git a/svtools/source/filter.vcl/wmf/winmtf.hxx b/svtools/source/filter.vcl/wmf/winmtf.hxx
index ada590a19675..f3b2482f63bc 100644
--- a/svtools/source/filter.vcl/wmf/winmtf.hxx
+++ b/svtools/source/filter.vcl/wmf/winmtf.hxx
@@ -672,6 +672,7 @@ class WinMtfOutput
void MoveClipRegion( const Size& rSize );
void SetClipPath( const PolyPolygon& rPolyPoly, sal_Int32 nClippingMode, sal_Bool bIsMapped );
void UpdateClipRegion();
+ void AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile );
WinMtfOutput( GDIMetaFile& rGDIMetaFile );
virtual ~WinMtfOutput();
@@ -734,6 +735,18 @@ private:
UINT16 nUnitsPerInch;
sal_uInt32 nRecSize;
+ // embedded EMF data
+ SvMemoryStream* pEMFStream;
+
+ // total number of comment records containing EMF data
+ sal_uInt32 nEMFRecCount;
+
+ // number of EMF records read
+ sal_uInt32 nEMFRec;
+
+ // total size of embedded EMF data
+ sal_uInt32 nEMFSize;
+
sal_uInt32 nSkipActions;
sal_uInt32 nCurrentAction;
sal_uInt32 nUnicodeEscapeAction;
@@ -755,6 +768,8 @@ public:
WMFReader( SvStream& rStreamWMF, GDIMetaFile& rGDIMetaFile, FilterConfigItem* pConfigItem = NULL )
: WinMtf( new WinMtfOutput( rGDIMetaFile ), rStreamWMF, pConfigItem ) {};
+ ~WMFReader();
+
// Liesst aus dem Stream eine WMF-Datei und fuellt das GDIMetaFile
void ReadWMF();
};
diff --git a/svtools/source/filter.vcl/wmf/winwmf.cxx b/svtools/source/filter.vcl/wmf/winwmf.cxx
index 0930b0ece8a8..54629383a4f8 100644
--- a/svtools/source/filter.vcl/wmf/winwmf.cxx
+++ b/svtools/source/filter.vcl/wmf/winwmf.cxx
@@ -32,6 +32,7 @@
#include "precompiled_svtools.hxx"
#include "winmtf.hxx"
+#include <vcl/gdimtf.hxx>
#include <rtl/crc.h>
#include <rtl/tencinfo.h>
#include <osl/endian.h>
@@ -831,81 +832,136 @@ void WMFReader::ReadRecordParams( USHORT nFunc )
pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
break;
}
- if ( nRecSize >= 12 ) // minimal escape lenght
+ if ( nRecSize >= 4 ) // minimal escape lenght
{
- sal_uInt16 nMode, nLen, OO;
- sal_uInt32 Magic, nCheck,nEsc;
+ sal_uInt16 nMode, nLen;
*pWMF >> nMode
- >> nLen
- >> OO
- >> Magic
- >> nCheck
- >> nEsc;
- if ( ( nMode == W_MFCOMMENT ) && ( nLen >= 14 ) && ( OO == 0x4f4f ) && ( Magic == 0xa2c2a ) )
+ >> nLen;
+ if ( ( nMode == W_MFCOMMENT ) && ( nLen >= 4 ) )
{
- sal_uInt32 nEscLen = nLen - 14;
- if ( nEscLen <= ( nRecSize * 2 ) )
+ sal_uInt32 nNewMagic; // we have to read int32 for
+ *pWMF >> nNewMagic; // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier
+
+ if( nNewMagic == 0x2c2a4f4f && nLen >= 14 )
{
+ sal_uInt16 nMagic2;
+ *pWMF >> nMagic2;
+ if( nMagic2 == 0x0a ) // 2nd half of magic
+ { // continue with private escape
+ sal_uInt32 nCheck, nEsc;
+ *pWMF >> nCheck
+ >> nEsc;
+
+ sal_uInt32 nEscLen = nLen - 14;
+ if ( nEscLen <= ( nRecSize * 2 ) )
+ {
#ifdef OSL_BIGENDIAN
- sal_uInt32 nTmp = SWAPLONG( nEsc );
- sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 );
+ sal_uInt32 nTmp = SWAPLONG( nEsc );
+ sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 );
#else
- sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 );
+ sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 );
#endif
- sal_Int8* pData = NULL;
+ sal_Int8* pData = NULL;
- if ( ( static_cast< sal_uInt64 >( nEscLen ) + pWMF->Tell() ) > nMetaRecEndPos )
- {
- pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
- break;
- }
- if ( nEscLen > 0 )
- {
- pData = new sal_Int8[ nEscLen ];
- pWMF->Read( pData, nEscLen );
- nCheckSum = rtl_crc32( nCheckSum, pData, nEscLen );
- }
- if ( nCheck == nCheckSum )
- {
- switch( nEsc )
- {
- case PRIVATE_ESCAPE_UNICODE :
- { // we will use text instead of polygons only if we have the correct font
- if ( aVDev.IsFontAvailable( pOut->GetFont().GetName() ) )
+ if ( ( static_cast< sal_uInt64 >( nEscLen ) + pWMF->Tell() ) > nMetaRecEndPos )
+ {
+ pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
+ break;
+ }
+ if ( nEscLen > 0 )
+ {
+ pData = new sal_Int8[ nEscLen ];
+ pWMF->Read( pData, nEscLen );
+ nCheckSum = rtl_crc32( nCheckSum, pData, nEscLen );
+ }
+ if ( nCheck == nCheckSum )
+ {
+ switch( nEsc )
{
- Point aPt;
- String aString;
- sal_uInt32 i, nStringLen, nDXCount;
- sal_Int32* pDXAry = NULL;
- SvMemoryStream aMemoryStream( nEscLen );
- aMemoryStream.Write( pData, nEscLen );
- aMemoryStream.Seek( STREAM_SEEK_TO_BEGIN );
- aMemoryStream >> aPt.X()
- >> aPt.Y()
- >> nStringLen;
-
- if ( ( static_cast< sal_uInt64 >( nStringLen ) * sizeof( sal_Unicode ) ) < ( nEscLen - aMemoryStream.Tell() ) )
- {
- sal_Unicode* pBuf = aString.AllocBuffer( (xub_StrLen)nStringLen );
- for ( i = 0; i < nStringLen; i++ )
- aMemoryStream >> pBuf[ i ];
- aMemoryStream >> nDXCount;
- if ( ( static_cast< sal_uInt64 >( nDXCount ) * sizeof( sal_Int32 ) ) >= ( nEscLen - aMemoryStream.Tell() ) )
- nDXCount = 0;
- if ( nDXCount )
- pDXAry = new sal_Int32[ nDXCount ];
- for ( i = 0; i < nDXCount; i++ )
- aMemoryStream >> pDXAry[ i ];
- aMemoryStream >> nSkipActions;
- pOut->DrawText( aPt, aString, pDXAry );
- delete[] pDXAry;
+ case PRIVATE_ESCAPE_UNICODE :
+ { // we will use text instead of polygons only if we have the correct font
+ if ( aVDev.IsFontAvailable( pOut->GetFont().GetName() ) )
+ {
+ Point aPt;
+ String aString;
+ sal_uInt32 i, nStringLen, nDXCount;
+ sal_Int32* pDXAry = NULL;
+ SvMemoryStream aMemoryStream( nEscLen );
+ aMemoryStream.Write( pData, nEscLen );
+ aMemoryStream.Seek( STREAM_SEEK_TO_BEGIN );
+ aMemoryStream >> aPt.X()
+ >> aPt.Y()
+ >> nStringLen;
+
+ if ( ( static_cast< sal_uInt64 >( nStringLen ) * sizeof( sal_Unicode ) ) < ( nEscLen - aMemoryStream.Tell() ) )
+ {
+ sal_Unicode* pBuf = aString.AllocBuffer( (xub_StrLen)nStringLen );
+ for ( i = 0; i < nStringLen; i++ )
+ aMemoryStream >> pBuf[ i ];
+ aMemoryStream >> nDXCount;
+ if ( ( static_cast< sal_uInt64 >( nDXCount ) * sizeof( sal_Int32 ) ) >= ( nEscLen - aMemoryStream.Tell() ) )
+ nDXCount = 0;
+ if ( nDXCount )
+ pDXAry = new sal_Int32[ nDXCount ];
+ for ( i = 0; i < nDXCount; i++ )
+ aMemoryStream >> pDXAry[ i ];
+ aMemoryStream >> nSkipActions;
+ pOut->DrawText( aPt, aString, pDXAry );
+ delete[] pDXAry;
+ }
+ }
}
+ break;
}
}
- break;
+ delete[] pData;
+ }
+ }
+ }
+ else if ( nNewMagic == 0x43464D57 && nLen >= 34 && ( nLen + 10 <= nRecSize * 2 ))
+ {
+ sal_uInt32 nComType, nVersion, nFlags, nComRecCount,
+ nCurRecSize, nRemainingSize, nEMFTotalSize;
+ sal_uInt16 nCheck;
+
+ *pWMF >> nComType >> nVersion >> nCheck >> nFlags
+ >> nComRecCount >> nCurRecSize
+ >> nRemainingSize >> nEMFTotalSize; // the nRemainingSize is not mentioned in MSDN documentation
+ // but it seems to be required to read in data produced by OLE
+
+ if( nComType == 0x01 && nVersion == 0x10000 && nComRecCount )
+ {
+ if( !nEMFRec )
+ { // first EMF comment
+ nEMFRecCount = nComRecCount;
+ nEMFSize = nEMFTotalSize;
+ pEMFStream = new SvMemoryStream( nEMFSize );
+ }
+ else if( ( nEMFRecCount != nComRecCount ) || ( nEMFSize != nEMFTotalSize ) ) // add additional checks here
+ {
+ // total records should be the same as in previous comments
+ nEMFRecCount = 0xFFFFFFFF;
+ delete pEMFStream;
+ pEMFStream = NULL;
+ }
+ nEMFRec++;
+
+ if( pEMFStream && nCurRecSize + 34 > nLen )
+ {
+ nEMFRecCount = 0xFFFFFFFF;
+ delete pEMFStream;
+ pEMFStream = NULL;
+ }
+
+ if( pEMFStream )
+ {
+ sal_Int8* pBuf = new sal_Int8[ nCurRecSize ];
+ sal_uInt32 nCount = pWMF->Read( pBuf, nCurRecSize );
+ if( nCount == nCurRecSize )
+ pEMFStream->Write( pBuf, nCount );
+ delete[] pBuf;
}
}
- delete[] pData;
}
}
}
@@ -1023,6 +1079,11 @@ void WMFReader::ReadWMF()
nCurrentAction = 0;
nUnicodeEscapeAction = 0;
+ pEMFStream = NULL;
+ nEMFRecCount = 0;
+ nEMFRec = 0;
+ nEMFSize = 0;
+
pOut->SetMapMode( MM_ANISOTROPIC );
pOut->SetWinOrg( Point() );
pOut->SetWinExt( Size( 1, 1 ) );
@@ -1070,6 +1131,33 @@ void WMFReader::ReadWMF()
ReadRecordParams( nFunction );
else
nSkipActions--;
+
+ if( pEMFStream && nEMFRecCount == nEMFRec )
+ {
+ GDIMetaFile aMeta;
+ pEMFStream->Seek( 0 );
+ EnhWMFReader* pEMFReader = new EnhWMFReader ( *pEMFStream, aMeta );
+ BOOL bRead = pEMFReader->ReadEnhWMF();
+ delete pEMFReader; // destroy first!!!
+
+ if( bRead )
+ {
+ pOut->AddFromGDIMetaFile( aMeta );
+ pOut->SetrclFrame( Rectangle(0, 0, aMeta.GetPrefSize().Width(), aMeta.GetPrefSize().Height() ));
+ // we have successfully read the embedded EMF data
+ // no need to process WMF data further
+ break;
+ }
+ else
+ {
+ // something went wrong
+ // continue with WMF, don't try this again
+ delete pEMFStream;
+ pEMFStream = NULL;
+ }
+
+ }
+
nPos += nRecSize * 2;
if ( nPos <= nEndPos )
pWMF->Seek( nPos );
@@ -1333,3 +1421,9 @@ sal_Bool WMFReader::GetPlaceableBound( Rectangle& rPlaceableBound, SvStream* pSt
return bRet;
}
+WMFReader::~WMFReader()
+{
+ if( pEMFStream )
+ delete pEMFStream;
+}
+
diff --git a/svtools/source/filter.vcl/wmf/wmfwr.cxx b/svtools/source/filter.vcl/wmf/wmfwr.cxx
index ee3a71c51f9d..f6ff58426a6a 100644
--- a/svtools/source/filter.vcl/wmf/wmfwr.cxx
+++ b/svtools/source/filter.vcl/wmf/wmfwr.cxx
@@ -33,6 +33,7 @@
#include <vcl/salbtype.hxx>
#include "wmfwr.hxx"
+#include "emfwr.hxx"
#include <vcl/fontcvt.hxx>
#include <rtl/crc.h>
#include <rtl/tencinfo.h>
@@ -1807,6 +1808,7 @@ BOOL WMFWriter::WriteWMF( const GDIMetaFile& rMTF, SvStream& rTargetStream,
{
WMFWriterAttrStackMember * pAt;
+ bEmbedEMF = TRUE;
bStatus=TRUE;
pConvert = 0;
pVirDev = new VirtualDevice;
@@ -1870,6 +1872,8 @@ BOOL WMFWriter::WriteWMF( const GDIMetaFile& rMTF, SvStream& rTargetStream,
CountActionsAndBitmaps(rMTF);
WriteHeader(rMTF,bPlaceable);
+ if( bEmbedEMF )
+ WriteEmbeddedEMF( rMTF );
WMFRecord_SetWindowOrg(Point(0,0));
WMFRecord_SetWindowExt(rMTF.GetPrefSize());
WMFRecord_SetBkMode( TRUE );
@@ -1948,3 +1952,79 @@ USHORT WMFWriter::CalcSaveTargetMapMode(MapMode& rMapMode,
return nDivisor;
}
+
+// ------------------------------------------------------------------------
+
+void WMFWriter::WriteEmbeddedEMF( const GDIMetaFile& rMTF )
+{
+ EMFWriter aEMFWriter;
+ SvMemoryStream aStream;
+ if( aEMFWriter.WriteEMF( rMTF, aStream ) )
+ {
+ aStream.Seek( 0 );
+ sal_Size nTotalSize = aStream.GetSize();
+ if( nTotalSize > SAL_MAX_UINT32 )
+ return;
+ sal_uInt32 nRemainingSize = static_cast< sal_uInt32 >( nTotalSize );
+ sal_uInt32 nRecCounts = ( (nTotalSize - 1) / 0x2000 ) + 1;
+ sal_uInt16 nCheckSum = 0, nWord;
+
+ sal_uInt32 nPos = 0;
+
+ while( nPos + 1 < nTotalSize )
+ {
+ aStream >> nWord;
+ nCheckSum ^= nWord;
+ nPos += 2;
+ }
+
+ nCheckSum = static_cast< sal_uInt16 >( nCheckSum * -1 );
+
+ aStream.Seek( 0 );
+ while( nRemainingSize > 0 )
+ {
+ sal_uInt32 nCurSize;
+ if( nRemainingSize > 0x2000 )
+ {
+ nCurSize = 0x2000;
+ nRemainingSize -= 0x2000;
+ }
+ else
+ {
+ nCurSize = nRemainingSize;
+ nRemainingSize = 0;
+ }
+ WriteEMFRecord( aStream,
+ nCurSize,
+ nRemainingSize,
+ nTotalSize,
+ nRecCounts,
+ nCheckSum );
+ nCheckSum = 0;
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void WMFWriter::WriteEMFRecord( SvMemoryStream& rStream, sal_uInt32 nCurSize, sal_uInt32 nRemainingSize,
+ sal_uInt32 nTotalSize, sal_uInt32 nRecCounts, sal_uInt16 nCheckSum )
+{
+ // according to http://msdn.microsoft.com/en-us/library/dd366152%28PROT.13%29.aspx
+ WriteRecordHeader( 0, W_META_ESCAPE );
+ *pWMF << (sal_uInt16)W_MFCOMMENT // same as META_ESCAPE_ENHANCED_METAFILE
+ << (sal_uInt16)( nCurSize + 34 ) // we will always have a 34 byte escape header:
+ << (sal_uInt32) 0x43464D57 // WMFC
+ << (sal_uInt32) 0x00000001 // Comment type
+ << (sal_uInt32) 0x00010000 // version
+ << nCheckSum // check sum
+ << (sal_uInt32) 0 // flags = 0
+ << nRecCounts // total number of records
+ << nCurSize // size of this record's data
+ << nRemainingSize // remaining size of data in following records, missing in MSDN documentation
+ << nTotalSize; // total size of EMF stream
+
+ pWMF->Write( static_cast< const sal_Char* >( rStream.GetData() ) + rStream.Tell(), nCurSize );
+ rStream.SeekRel( nCurSize );
+ UpdateRecordHeader();
+}
diff --git a/svtools/source/filter.vcl/wmf/wmfwr.hxx b/svtools/source/filter.vcl/wmf/wmfwr.hxx
index 48986a280404..a98b496a17e2 100644
--- a/svtools/source/filter.vcl/wmf/wmfwr.hxx
+++ b/svtools/source/filter.vcl/wmf/wmfwr.hxx
@@ -128,6 +128,8 @@ private:
ULONG nWrittenBitmaps; // Anzahl der bereits geschriebenen Bitmaps
ULONG nActBitmapPercent; // Wieviel Prozent die naechste Bitmap schon geschrieben ist.
+ BOOL bEmbedEMF; // optionally embedd EMF data into WMF
+
void MayCallback();
// Berechnet anhand der obigen 5 Parameter eine Prozentzahl
// und macht dann ggf. einen Callback. Setzt bStatus auf FALSE wenn User abbrechen
@@ -207,6 +209,13 @@ private:
void WriteHeader(const GDIMetaFile & rMTF, BOOL bPlaceable);
void UpdateHeader();
+ void WriteEmbeddedEMF( const GDIMetaFile& rMTF );
+ void WriteEMFRecord( SvMemoryStream& rStream, sal_uInt32 nCurSize,
+ sal_uInt32 nRemainingSize,
+ sal_uInt32 nTotalSize,
+ sal_uInt32 nRecCounts,
+ sal_uInt16 nCheckSum );
+
USHORT CalcSaveTargetMapMode(MapMode& rMapMode, const Size& rPrefSize);
public: