Hi,
I have submitted a patch for review:
https://gerrit.libreoffice.org/3839
To pull it, you can do:
git pull ssh://gerrit.libreoffice.org:29418/core refs/changes/39/3839/1
Enhancements to VCL metafile handling
* Remove EMFP_DEBUG with OSL_DEBUG conditional defines and SAL_INFO
* While we are about it, to help with troubleshooting metafile
issues, add another vcl.emf area to log-areas.dox
* Improve error handling when processing an EMF header:
+ replace variable name nsal_uInt32 (!!) with sane variables
to make the code more readable
+ check to ensure that type field is 0x1, which is all it can be
for metafiles
+ check that signature field is set to ASCII-encoded value "FME"
+ loose check of version field to see if it is 0x00010000
+ warn if record count is zero - that really shouldn't be possible
+ check bytes field in header to make sure it correlates to the
actual size of the metafile
* Quite a few more comments in the code to clarify the intended
structure of a metafile, per [MS-EMF] documentation
Change-Id: Id4ed486b2dd0c6e7bdee67cb344aaaf8e8d98f84
---
M include/sal/log-areas.dox
M vcl/source/filter/wmf/enhwmf.cxx
2 files changed, 78 insertions(+), 32 deletions(-)
diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
index 693450b..cf1f1cc 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -260,6 +260,7 @@
@li @c vcl.atsui - ATSUI (obsolete) -using code for Mac OS X
@li @c vcl.control
@li @c vcl.coretext - CoreText-using code for Mac OS X and iOS
+@li @c vcl.emf - EMF/EMF+ processing
@li @c vcl.fonts - font-specific code
@li @c vcl.gdi - the GDI part of VCL, devices, bitmaps, etc.
@li @c vcl.gtk - Gtk+ 2/3 plugin
diff --git a/vcl/source/filter/wmf/enhwmf.cxx b/vcl/source/filter/wmf/enhwmf.cxx
index cd71a6b..298cd1e 100644
--- a/vcl/source/filter/wmf/enhwmf.cxx
+++ b/vcl/source/filter/wmf/enhwmf.cxx
@@ -151,12 +151,6 @@
#define EMR_SETLINKEDUFIS 119
#define EMR_SETTEXTJUSTIFICATION 120
-#if OSL_DEBUG_LEVEL > 1
-#define EMFP_DEBUG(x) x
-#else
-#define EMFP_DEBUG(x)
-#endif
-
#ifdef OSL_BIGENDIAN
// currently unused
@@ -226,24 +220,27 @@
return bOk;
}
-EMFP_DEBUG(void dumpWords( SvStream& s, int i )
+#if OSL_DEBUG_LEVEL > 1
+void dumpWords( SvStream& s, int i )
{
sal_uInt32 pos = s.Tell();
sal_Int16 data;
for( ; i > 0; i -- ) {
s >> data;
- EMFP_DEBUG(printf ("\t\t\tdata: %04hx\n", data));
+ SAL_INFO("vcl.emf", "\t\t\tdata: " << std::hex << data);
}
s.Seek (pos);
-});
+};
+#endif
void EnhWMFReader::ReadEMFPlusComment(sal_uInt32 length, sal_Bool& bHaveDC)
{
if (!bEMFPlus) {
pOut->PassEMFPlusHeaderInfo();
+#if OSL_DEBUG_LEVEL > 1
// debug code - write the stream to debug file /tmp/emf-stream.emf
- EMFP_DEBUG(int pos = pWMF->Tell();
+ int pos = pWMF->Tell();
pWMF->Seek(0);
SvFileStream file( OUString( "/tmp/emf-stream.emf" ), STREAM_WRITE | STREAM_TRUNC );
@@ -251,7 +248,9 @@
file.Flush();
file.Close();
- pWMF->Seek( pos );)
+ pWMF->Seek( pos );
+#endif
+
}
bEMFPlus = true;
@@ -265,7 +264,7 @@
OSL_ASSERT(length >= 4);
// reduce by 32bit length itself, skip in SeekRel if
- // impossibly unavailble
+ // impossibly unavailable
sal_uInt32 nRemainder = length >= 4 ? length-4 : length;
const size_t nRequiredHeaderSize = 12;
@@ -277,12 +276,12 @@
*pWMF >> type >> flags >> size >> dataSize;
nRemainder -= nRequiredHeaderSize;
- EMFP_DEBUG(printf ("\t\tEMF+ record type: %d\n", type));
+ SAL_INFO ("vcl.emf", "\t\tEMF+ record type: " << std::hex << type);
// GetDC
if( type == 16388 ) {
bHaveDC = true;
- EMFP_DEBUG(printf ("\t\tEMF+ lock DC (device context)\n"));
+ SAL_INFO ("vcl.emf", "\t\tEMF+ lock DC (device context)");
}
// Get the length of the remaining data of this record based
@@ -454,26 +453,27 @@
if( !aBmpSaveList.empty()
&& ( nRecType != EMR_STRETCHBLT )
&& ( nRecType != EMR_STRETCHDIBITS )
- )
+ ) {
pOut->ResolveBitmapActions( aBmpSaveList );
+ }
bFlag = sal_False;
- EMFP_DEBUG(printf ("0x%04x-0x%04x record type: %d size: %d\n",(unsigned int) (nNextPos -
nRecSize),(unsigned int) nNextPos, (int)nRecType,(int) nRecSize));
+ SAL_INFO ("vcl.emf", "0x" << std::hex << (nNextPos - nRecSize) << "-0x" << nNextPos << "
record type: " << std::dec << nRecType << " size: " << nRecSize);
if( bEnableEMFPlus && nRecType == EMR_GDICOMMENT ) {
sal_uInt32 length;
*pWMF >> length;
- EMFP_DEBUG(printf ("\tGDI comment\n\t\tlength: %d\n", (int)length));
+ SAL_INFO("vcl.emf", "\tGDI comment\n\t\tlength: " << length);
if( pWMF->good() && length >= 4 ) {
sal_uInt32 id;
*pWMF >> id;
- EMFP_DEBUG(printf ("\t\tbegin %c%c%c%c id: 0x%x\n", (char)(id & 0xff), (char)((id
& 0xff00) >> 8), (char)((id & 0xff0000) >> 16), (char)((id & 0xff000000) >> 24), (unsigned int)id));
+ SAL_INFO ("vcl.emf", "\t\tbegin " << (char)(id & 0xff) << (char)((id & 0xff00) >>
8) << (char)((id & 0xff0000) >> 16) << (char)((id & 0xff000000) >> 24) << " id: 0x" << std::hex <<
id);
// EMF+ comment (FIXME: BE?)
if( id == 0x2B464D45 && nRecSize >= 12 )
@@ -482,7 +482,7 @@
else if( id == 0x43494447 && nRecSize >= 12 ) {
// TODO: ReadGDIComment()
} else {
- EMFP_DEBUG(printf ("\t\tunknown id: 0x%x\n",(unsigned int) id));
+ SAL_INFO ("vcl.emf", "\t\tunknown id: 0x" << std::hex << id);
}
}
}
@@ -1341,16 +1341,21 @@
sal_Bool EnhWMFReader::ReadHeader()
{
- sal_uInt32 nsal_uInt32, nHeaderSize, nPalEntries;
+ sal_uInt32 nType, nSignature, nVersion;
+ sal_uInt32 nHeaderSize, nPalEntries;
sal_Int32 nLeft, nTop, nRight, nBottom;
// Spare me the METAFILEHEADER here
- // Reading the METAHEADER
- *pWMF >> nsal_uInt32 >> nHeaderSize;
- if ( nsal_uInt32 != 1 ) // Type
+ // Reading the METAHEADER - EMR_HEADER ([MS-EMF] section 2.3.4.2 EMR_HEADER Record Types)
+ *pWMF >> nType >> nHeaderSize;
+ if ( nType != 1 ) { // per [MS-EMF] 2.3.4.2 EMF Header Record Types, type MUST be 0x00000001
+ SAL_WARN("vcl.emf", "EMF header type is not set to 0x00000001 - possibly corrupted file?");
return sal_False;
+ }
- // bound size
+ // Start reading the EMR_HEADER Header object
+
+ // bound size (RectL object, see [MS-WMF] section 2.2.2.19)
Rectangle rclBounds; // rectangle in logical units
*pWMF >> nLeft >> nTop >> nRight >> nBottom;
rclBounds.Left() = nLeft;
@@ -1358,7 +1363,7 @@
rclBounds.Right() = nRight;
rclBounds.Bottom() = nBottom;
- // picture frame size
+ // picture frame size (RectL object)
Rectangle rclFrame; // rectangle in device units 1/100th mm
*pWMF >> nLeft >> nTop >> nRight >> nBottom;
rclFrame.Left() = nLeft;
@@ -1366,27 +1371,67 @@
rclFrame.Right() = nRight;
rclFrame.Bottom() = nBottom;
- *pWMF >> nsal_uInt32; // signature
+ *pWMF >> nSignature;
- if ( nsal_uInt32 != 0x464d4520 )
+ // nSignature MUST be the ASCII characters "FME", see [WS-EMF] 2.2.9 Header Object
+ // and 2.1.14 FormatSignature Enumeration
+ if ( nSignature != 0x464d4520 ) {
+ SAL_WARN("vcl.emf", "EMF\t\tSignature is not 0x464d4520 (\"FME\") - possibly corrupted
file?");
return sal_False;
+ }
- *pWMF >> nsal_uInt32; // nVersion
+ *pWMF >> nVersion; // according to [WS-EMF] 2.2.9, this SHOULD be 0x0001000, however
+ // Microsoft note that not even Windows checks this...
+ if ( nVersion != 0x00010000 ) {
+ SAL_WARN("vcl.emf", "EMF\t\tThis really should be 0x00010000, though not absolutely
essential...");
+ }
+
*pWMF >> nEndPos; // size of metafile
nEndPos += nStartPos;
sal_uInt32 nStrmPos = pWMF->Tell(); // checking if nEndPos is valid
pWMF->Seek( STREAM_SEEK_TO_END );
- if ( pWMF->Tell() < nEndPos )
- nEndPos = pWMF->Tell();
+ sal_uInt32 nActualFileSize = pWMF->Tell();
+
+ if ( nActualFileSize < nEndPos ) {
+ SAL_WARN("vcl.emf", "EMF\t\tEMF Header object records number of bytes as " << nEndPos
+ << ", however the file size is actually " << nActualFileSize
+ << " bytes. Possible file corruption?");
+ nEndPos = nActualFileSize;
+ }
pWMF->Seek( nStrmPos );
*pWMF >> nRecordCount;
- if ( !nRecordCount )
+ if ( !nRecordCount ) {
+ SAL_WARN("vcl.emf", "EMF\t\tEMF Header object shows record counter as 0! This shouldn't "
+ "be possible... indicator of possible file corruption?");
return sal_False;
+ }
- pWMF->SeekRel( 0xc );
+ // the number of "handles", or graphics objects used in the metafile
+
+ sal_uInt16 nHandlesCount;
+ *pWMF >> nHandlesCount;
+
+ // the next 2 bytes are reserved, but according to [MS-EMF] section 2.2.9
+ // it MUST be 0x000 and MUST be ignored... the thing is, having such a specific
+ // value is actually pretty useful in checking if there is possible corruption
+
+ sal_uInt16 nReserved;
+ *pWMF >> nReserved;
+
+ if ( nReserved != 0x0000 ) {
+ SAL_WARN("vcl.emf", "EMF\t\tEMF Header object's reserved field is NOT 0x0000... possible "
+ "corruption?");
+ }
+
+ // The next 4 bytes is specifies the number of characters in the metafile description
+ // the 4 bytes after that specific the offset from this record that contains the
+ // metafile description... zero means no description string.
+ // For now, we ignore it.
+
+ pWMF->SeekRel( 0x8 );
sal_Int32 nPixX, nPixY, nMillX, nMillY;
*pWMF >> nPalEntries >> nPixX >> nPixY >> nMillX >> nMillY;
--
To view, visit https://gerrit.libreoffice.org/3839
To unsubscribe, visit https://gerrit.libreoffice.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Id4ed486b2dd0c6e7bdee67cb344aaaf8e8d98f84
Gerrit-PatchSet: 1
Gerrit-Project: core
Gerrit-Branch: master
Gerrit-Owner: Chris Sherlock <chris.sherlock79@gmail.com>
Context
- [PATCH] Enhancements to VCL metafile handling · Chris Sherlock (via Code Review)
Privacy Policy |
Impressum (Legal Info) |
Copyright information: Unless otherwise specified, all text and images
on this website are licensed under the
Creative Commons Attribution-Share Alike 3.0 License.
This does not include the source code of LibreOffice, which is
licensed under the Mozilla Public License (
MPLv2).
"LibreOffice" and "The Document Foundation" are
registered trademarks of their corresponding registered owners or are
in actual use as trademarks in one or more countries. Their respective
logos and icons are also subject to international copyright laws. Use
thereof is explained in our
trademark policy.