Kaydet (Commit) 975ab665 authored tarafından Mike Kaganski's avatar Mike Kaganski Kaydeden (comit) Miklos Vajna

tdf#93750 allow for EMF+ record padding up to 11 bytes

When an array of EMF+ has extra bytes in the end, that are less than 12,
they should not be  treated as another EMF+ record, but simply ignored.

Change-Id: I34701c00916812c8a6a4b69730f602da81719b35
Reviewed-on: https://gerrit.libreoffice.org/18110Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarAndras Timar <andras.timar@collabora.com>
(cherry picked from commit daecb93a)
Reviewed-on: https://gerrit.libreoffice.org/18200Reviewed-by: 's avatarMiklos Vajna <vmiklos@collabora.co.uk>
üst f85ed94f
...@@ -1111,31 +1111,35 @@ namespace cppcanvas ...@@ -1111,31 +1111,35 @@ namespace cppcanvas
void Read (SvMemoryStream &s, sal_uInt32 dataSize, bool bUseWholeStream) void Read (SvMemoryStream &s, sal_uInt32 dataSize, bool bUseWholeStream)
{ {
sal_uInt32 header, unknown; sal_uInt32 header, bitmapType;
s.ReadUInt32( header ).ReadUInt32( type ); s.ReadUInt32( header ).ReadUInt32( type );
SAL_INFO("cppcanvas.emf", "EMF+\timage\nEMF+\theader: 0x" << std::hex << header << " type: " << type << std::dec ); SAL_INFO("cppcanvas.emf", "EMF+\timage\nEMF+\theader: 0x" << std::hex << header << " type: " << type << std::dec );
if (type == 1) { // bitmap if (type == 1) { // bitmap
s.ReadInt32( width ).ReadInt32( height ).ReadInt32( stride ).ReadInt32( pixelFormat ).ReadUInt32( unknown ); s.ReadInt32( width ).ReadInt32( height ).ReadInt32( stride ).ReadInt32( pixelFormat ).ReadUInt32( bitmapType );
SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << width << " height: " << height << " stride: " << stride << " pixelFormat: 0x" << std::hex << pixelFormat << std::dec); SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << width << " height: " << height << " stride: " << stride << " pixelFormat: 0x" << std::hex << pixelFormat << std::dec);
if (width == 0) { // non native formats if ((bitmapType != 0) || (width == 0)) { // non native formats
GraphicFilter filter; GraphicFilter filter;
filter.ImportGraphic (graphic, OUString(), s); filter.ImportGraphic (graphic, OUString(), s);
SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << graphic.GetBitmap().GetSizePixel().Width() << " height: " << graphic.GetBitmap().GetSizePixel().Height()); SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << graphic.GetBitmap().GetSizePixel().Width() << " height: " << graphic.GetBitmap().GetSizePixel().Height());
} }
} else if (type == 2) { } else if (type == 2) { // metafile
sal_Int32 mfType, mfSize; sal_Int32 mfType, mfSize;
s.ReadInt32( mfType ).ReadInt32( mfSize ); s.ReadInt32( mfType ).ReadInt32( mfSize );
SAL_INFO("cppcanvas.emf", "EMF+\tmetafile type: " << mfType << " dataSize: " << mfSize << " real size calculated from record dataSize: " << dataSize - 16); if (bUseWholeStream)
dataSize = s.remainingSize();
else
dataSize -= 16;
SAL_INFO("cppcanvas.emf", "EMF+\tmetafile type: " << mfType << " dataSize: " << mfSize << " real size calculated from record dataSize: " << dataSize);
GraphicFilter filter; GraphicFilter filter;
// workaround buggy metafiles, which have wrong mfSize set (n#705956 for example) // workaround buggy metafiles, which have wrong mfSize set (n#705956 for example)
SvMemoryStream mfStream (const_cast<char *>(static_cast<char const *>(s.GetData()) + s.Tell()), bUseWholeStream ? s.remainingSize() : dataSize - 16, StreamMode::READ); SvMemoryStream mfStream (const_cast<char *>(static_cast<char const *>(s.GetData()) + s.Tell()), dataSize, StreamMode::READ);
filter.ImportGraphic (graphic, OUString(), mfStream); filter.ImportGraphic (graphic, OUString(), mfStream);
...@@ -1810,9 +1814,12 @@ namespace cppcanvas ...@@ -1810,9 +1814,12 @@ namespace cppcanvas
sal_uInt32 length = pAct->GetDataSize (); sal_uInt32 length = pAct->GetDataSize ();
SvMemoryStream rMF ((void*) pAct->GetData (), length, StreamMode::READ); SvMemoryStream rMF ((void*) pAct->GetData (), length, StreamMode::READ);
length -= 4; if (length < 12) {
SAL_INFO("cppcanvas.emf", "length is less than required header size");
}
while (length > 0) { // 12 is minimal valid EMF+ record size; remaining bytes are padding
while (length >= 12) {
sal_uInt16 type, flags; sal_uInt16 type, flags;
sal_uInt32 size, dataSize; sal_uInt32 size, dataSize;
sal_Size next; sal_Size next;
...@@ -1823,6 +1830,11 @@ namespace cppcanvas ...@@ -1823,6 +1830,11 @@ namespace cppcanvas
if (size < 12) { if (size < 12) {
SAL_INFO("cppcanvas.emf", "Size field is less than 12 bytes"); SAL_INFO("cppcanvas.emf", "Size field is less than 12 bytes");
} else if (size > length) {
SAL_INFO("cppcanvas.emf", "Size field is greater than bytes left");
}
if (dataSize > (size-12)) {
SAL_INFO("cppcanvas.emf", "DataSize field is greater than Size-12");
} }
SAL_INFO("cppcanvas.emf", "EMF+ record size: " << size << " type: " << emfTypeToName(type) << " flags: " << flags << " data size: " << dataSize); SAL_INFO("cppcanvas.emf", "EMF+ record size: " << size << " type: " << emfTypeToName(type) << " flags: " << flags << " data size: " << dataSize);
...@@ -1834,14 +1846,15 @@ namespace cppcanvas ...@@ -1834,14 +1846,15 @@ namespace cppcanvas
mMStream.Seek(0); mMStream.Seek(0);
} }
// 1st 4 bytes are unknown OSL_ENSURE(dataSize >= 4, "No room for TotalObjectSize in EmfPlusContinuedObjectRecord");
// 1st 4 bytes are TotalObjectSize
mMStream.Write (static_cast<const char *>(rMF.GetData()) + rMF.Tell() + 4, dataSize - 4); mMStream.Write (static_cast<const char *>(rMF.GetData()) + rMF.Tell() + 4, dataSize - 4);
SAL_INFO("cppcanvas.emf", "EMF+ read next object part size: " << size << " type: " << type << " flags: " << flags << " data size: " << dataSize); SAL_INFO("cppcanvas.emf", "EMF+ read next object part size: " << size << " type: " << type << " flags: " << flags << " data size: " << dataSize);
} else { } else {
if (mbMultipart) { if (mbMultipart) {
SAL_INFO("cppcanvas.emf", "EMF+ multipart record flags: " << mMFlags); SAL_INFO("cppcanvas.emf", "EMF+ multipart record flags: " << mMFlags);
mMStream.Seek (0); mMStream.Seek (0);
processObjectRecord (mMStream, mMFlags, dataSize, true); processObjectRecord (mMStream, mMFlags, 0, true);
} }
mbMultipart = false; mbMultipart = false;
} }
......
...@@ -44,12 +44,14 @@ public: ...@@ -44,12 +44,14 @@ public:
void testSine(); void testSine();
void testEmfProblem(); void testEmfProblem();
void testWorldTransformFontSize(); void testWorldTransformFontSize();
void testTdf93750();
CPPUNIT_TEST_SUITE(WmfTest); CPPUNIT_TEST_SUITE(WmfTest);
CPPUNIT_TEST(testNonPlaceableWmf); CPPUNIT_TEST(testNonPlaceableWmf);
CPPUNIT_TEST(testSine); CPPUNIT_TEST(testSine);
CPPUNIT_TEST(testEmfProblem); CPPUNIT_TEST(testEmfProblem);
CPPUNIT_TEST(testWorldTransformFontSize); CPPUNIT_TEST(testWorldTransformFontSize);
CPPUNIT_TEST(testTdf93750);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
}; };
...@@ -148,6 +150,21 @@ void WmfTest::testWorldTransformFontSize() ...@@ -148,6 +150,21 @@ void WmfTest::testWorldTransformFontSize()
assertXPath(pDoc, "/metafile/font[3]", "weight", "normal"); assertXPath(pDoc, "/metafile/font[3]", "weight", "normal");
} }
void WmfTest::testTdf93750()
{
SvFileStream aFileStream(getFullUrl("tdf93750.emf"), StreamMode::READ);
GDIMetaFile aGDIMetaFile;
ReadWindowMetafile(aFileStream, aGDIMetaFile);
MetafileXmlDump dumper;
xmlDocPtr pDoc = dumper.dumpAndParse(aGDIMetaFile);
CPPUNIT_ASSERT (pDoc);
assertXPath(pDoc, "/metafile/push[1]/comment[2]", "datasize", "28");
assertXPath(pDoc, "/metafile/push[1]/comment[3]", "datasize", "72");
}
CPPUNIT_TEST_SUITE_REGISTRATION(WmfTest); CPPUNIT_TEST_SUITE_REGISTRATION(WmfTest);
CPPUNIT_PLUGIN_IMPLEMENT(); CPPUNIT_PLUGIN_IMPLEMENT();
......
...@@ -433,10 +433,8 @@ void EnhWMFReader::ReadEMFPlusComment(sal_uInt32 length, bool& bHaveDC) ...@@ -433,10 +433,8 @@ void EnhWMFReader::ReadEMFPlusComment(sal_uInt32 length, bool& bHaveDC)
bHaveDC = false; bHaveDC = false;
OSL_ASSERT(length >= 4); // skip in SeekRel if impossibly unavailable
// reduce by 32bit length itself, skip in SeekRel if sal_uInt32 nRemainder = length;
// impossibly unavailable
sal_uInt32 nRemainder = length >= 4 ? length-4 : length;
const size_t nRequiredHeaderSize = 12; const size_t nRequiredHeaderSize = 12;
while (nRemainder >= nRequiredHeaderSize) while (nRemainder >= nRequiredHeaderSize)
...@@ -682,7 +680,9 @@ bool EnhWMFReader::ReadEnhWMF() ...@@ -682,7 +680,9 @@ bool EnhWMFReader::ReadEnhWMF()
// EMF+ comment (FIXME: BE?) // EMF+ comment (FIXME: BE?)
if( id == 0x2B464D45 && nRecSize >= 12 ) if( id == 0x2B464D45 && nRecSize >= 12 )
ReadEMFPlusComment( length, bHaveDC ); // [MS-EMF] 2.3.3: DataSize includes both CommentIdentifier and CommentRecordParm fields.
// We have already read 4-byte CommentIdentifier, so reduce length appropriately
ReadEMFPlusComment( length-4, bHaveDC );
// GDIC comment, doesn't do anything useful yet // GDIC comment, doesn't do anything useful yet
else if( id == 0x43494447 && nRecSize >= 12 ) { else if( id == 0x43494447 && nRecSize >= 12 ) {
// TODO: ReadGDIComment() // TODO: ReadGDIComment()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment