1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <IDocumentContentOperations.hxx>
22 #include "writerhelper.hxx"
23 #include <com/sun/star/embed/XClassifiedObject.hpp>
24 #include <com/sun/star/embed/Aspects.hpp>
28 #include <osl/endian.h>
29 #include <sot/storage.hxx>
30 #include <com/sun/star/drawing/XShape.hpp>
31 #include <hintids.hxx>
32 #include <svx/svdoole2.hxx>
33 #include <filter/msfilter/msdffimp.hxx>
34 #include <sprmids.hxx>
35 #include <svx/unoapi.hxx>
37 #include <sot/exchange.hxx>
38 #include <swtypes.hxx>
39 #include <fmtanchr.hxx>
40 #include <fmtcntnt.hxx>
41 #include <dcontact.hxx>
47 #include <redline.hxx>
48 #include <fltshell.hxx>
49 #include <unodraw.hxx>
50 #include <shellio.hxx>
53 #include <vcl/graphicfilter.hxx>
54 #include <vcl/wmf.hxx>
56 #include "ww8scan.hxx"
58 #include "ww8par2.hxx"
62 sal_Int16 mm
; // 0x6 int
63 sal_Int16 xExt
; // 0x8 int in 1/100 mm
64 sal_Int16 yExt
; // 0xa int in 1/100 mm
65 sal_Int16 hMF
; // 0xc int
68 using namespace ::com::sun::star
;
70 static bool SwWw8ReadScaling(long& rX
, long& rY
, tools::SvRef
<SotStorage
>& rSrc1
)
72 // Getting the scaling factor:
73 // Information in the PIC-stream (by trying out)
75 // 0x08 .. 0x0a Flags ??
76 // 0x08 contains: 1 / 0
77 // 0x09 contains: 0,8,0x18
78 // 0x0a contains: always 8, MAP_ANISOTROPIC ???
79 // 0x0b contains: always 0
80 // 0x0c, 0x10 original size x,y in 1/100 mm
81 // 0x14, 0x16 original size x,y in tw
82 // 0x2c, 0x30 scaling x,y in per thousand
83 // 0x34, 0x38, 0x3c, 0x40 Crop Left, Top, Right, Bot in tw
85 tools::SvRef
<SotStorageStream
> xSrc3
= rSrc1
->OpenSotStream( "\3PIC",
86 StreamMode::STD_READ
);
87 SotStorageStream
* pS
= xSrc3
.get();
88 pS
->SetEndian( SvStreamEndian::LITTLE
);
89 pS
->Seek( STREAM_SEEK_TO_END
);
91 OSL_ENSURE( pS
->Tell() >= 76, "+OLE-PIC-Stream is shorter than 76 Byte" );
102 pS
->ReadInt32( nOrgWidth
) // Original Size in 1/100 mm
103 .ReadInt32( nOrgHeight
);
105 pS
->ReadInt32( nScaleX
) // Scaling in Promille
106 .ReadInt32( nScaleY
)
107 .ReadInt32( nCropLeft
) // Cropping in 1/100 mm
108 .ReadInt32( nCropTop
)
109 .ReadInt32( nCropRight
)
110 .ReadInt32( nCropBottom
);
112 rX
= nOrgWidth
- nCropLeft
- nCropRight
;
113 rY
= nOrgHeight
- nCropTop
- nCropBottom
;
114 if (10 > nScaleX
|| 65536 < nScaleX
|| 10 > nScaleY
|| 65536 < nScaleY
)
116 OSL_ENSURE( !pS
, "+OLE-scaling information in PIC-stream wrong" );
121 rX
= (rX
* nScaleX
) / 1000;
122 rY
= (rY
* nScaleY
) / 1000;
127 static bool SwWw6ReadMetaStream(GDIMetaFile
& rWMF
, OLE_MFP
* pMfp
,
128 tools::SvRef
<SotStorage
>& rSrc1
)
130 tools::SvRef
<SotStorageStream
> xSrc2
= rSrc1
->OpenSotStream( "\3META",
131 StreamMode::STD_READ
);
132 SotStorageStream
* pSt
= xSrc2
.get();
133 pSt
->SetEndian( SvStreamEndian::LITTLE
);
134 size_t const nRead
= pSt
->ReadBytes(pMfp
, sizeof(*pMfp
));
135 // read mini-placable-header
136 if (nRead
!= sizeof(*pMfp
))
139 #if defined OSL_BIGENDIAN
140 pMfp
->mm
= OSL_SWAPWORD( pMfp
->mm
);
141 pMfp
->xExt
= OSL_SWAPWORD( pMfp
->xExt
);
142 pMfp
->yExt
= OSL_SWAPWORD( pMfp
->yExt
);
143 #endif // OSL_BIGENDIAN
145 if( pMfp
->mm
== 94 || pMfp
->mm
== 99 )
147 SAL_WARN("sw.ww8", "+OLE: wrong metafile type");
152 SAL_WARN("sw.ww8", "OLE: wrong mMetafile type (not anisotropic)");
154 if( !pMfp
->xExt
|| !pMfp
->yExt
)
156 SAL_WARN("sw.ww8", "+OLE: size of 0?");
159 bool bOk
= ReadWindowMetafile( *pSt
, rWMF
); // read WMF
160 // *pSt >> aWMF doesn't work without the placable header
161 if (!bOk
|| pSt
->GetError() || rWMF
.GetActionSize() == 0)
163 SAL_WARN("sw.ww8", "+OLE: could not read the metafile");
167 rWMF
.SetPrefMapMode( MapMode( MapUnit::Map100thMM
) );
169 // Scale MetaFile to new size and save new size to MetaFile
170 Size
aOldSiz( rWMF
.GetPrefSize() );
171 Size
aNewSiz( pMfp
->xExt
, pMfp
->yExt
);
172 Fraction
aFracX( aNewSiz
.Width(), aOldSiz
.Width() );
173 Fraction
aFracY( aNewSiz
.Height(), aOldSiz
.Height() );
175 rWMF
.Scale( aFracX
, aFracY
);
176 rWMF
.SetPrefSize( aNewSiz
);
181 static bool SwWw6ReadMacPICTStream(Graphic
& rGraph
, tools::SvRef
<SotStorage
>& rSrc1
)
183 // 03-META-stream does not exist. Maybe a 03-PICT?
184 tools::SvRef
<SotStorageStream
> xSrc4
= rSrc1
->OpenSotStream("\3PICT");
185 SotStorageStream
* pStp
= xSrc4
.get();
186 pStp
->SetEndian( SvStreamEndian::LITTLE
);
187 sal_uInt8 aTestA
[10]; // Does the 01Ole-stream even exist?
188 size_t const nReadTst
= pStp
->ReadBytes(aTestA
, sizeof(aTestA
));
189 if (nReadTst
!= sizeof(aTestA
))
192 pStp
->Seek( STREAM_SEEK_TO_BEGIN
);
194 // Mac-Pict is in the 03PICT-StorageStream but without the first 512 Bytes
195 // which are not relevant in a MAC-PICT (they are not evaluated)
196 return SwWW8ImplReader::GetPictGrafFromStream(rGraph
, *pStp
);
199 SwFlyFrameFormat
* SwWW8ImplReader::InsertOle(SdrOle2Obj
&rObject
,
200 const SfxItemSet
&rFlySet
, const SfxItemSet
*rGrfSet
)
202 SfxObjectShell
*pPersist
= m_rDoc
.GetPersist();
203 OSL_ENSURE(pPersist
, "No persist, cannot insert objects correctly");
207 SwFlyFrameFormat
*pRet
= nullptr;
209 SfxItemSet
*pMathFlySet
= nullptr;
210 uno::Reference
< embed::XClassifiedObject
> xClass( rObject
.GetObjRef(), uno::UNO_QUERY
);
213 SvGlobalName
aClassName( xClass
->getClassID() );
214 if (SotExchange::IsMath(aClassName
))
216 // StarMath sets it own fixed size, so its counter productive to use
217 // the size word says it is. i.e. Don't attempt to override its size.
218 pMathFlySet
= new SfxItemSet(rFlySet
);
219 pMathFlySet
->ClearItem(RES_FRM_SIZE
);
224 Take complete responsibility of the object away from SdrOle2Obj and to
225 me here locally. This utility class now owns the object.
228 // TODO/MBA: is the object inserted multiple times here? Testing!
229 // And is it a problem that we now use the same naming scheme as in the other apps?
230 sw::hack::DrawingOLEAdaptor
aOLEObj(rObject
, *pPersist
);
232 bool bSuccess
= aOLEObj
.TransferToDoc(sNewName
);
234 OSL_ENSURE(bSuccess
, "Insert OLE failed");
237 const SfxItemSet
*pFlySet
= pMathFlySet
? pMathFlySet
: &rFlySet
;
238 pRet
= m_rDoc
.getIDocumentContentOperations().InsertOLE(*m_pPaM
, sNewName
, rObject
.GetAspect(), pFlySet
, rGrfSet
);
244 SwFrameFormat
* SwWW8ImplReader::ImportOle(const Graphic
* pGrf
,
245 const SfxItemSet
* pFlySet
, const SfxItemSet
*pGrfSet
, const Rectangle
& aVisArea
)
247 ::SetProgressState(m_nProgress
, m_pDocShell
); // Update
248 SwFrameFormat
* pFormat
= nullptr;
253 SdrObject
* pRet
= ImportOleBase(aGraph
, pGrf
, pFlySet
, aVisArea
);
256 SfxItemSet
* pTempSet
= nullptr;
259 pTempSet
= new SfxItemSet( m_rDoc
.GetAttrPool(), RES_FRMATR_BEGIN
,
264 // Remove distance/borders
266 Reader::ResetFrameFormatAttrs( *pTempSet
);
268 SwFormatAnchor
aAnchor( FLY_AS_CHAR
);
269 aAnchor
.SetAnchor( m_pPaM
->GetPoint() );
270 pTempSet
->Put( aAnchor
);
272 const Size aSizeTwip
= OutputDevice::LogicToLogic(
273 aGraph
.GetPrefSize(), aGraph
.GetPrefMapMode(), MapUnit::MapTwip
);
275 pTempSet
->Put( SwFormatFrameSize( ATT_FIX_SIZE
, aSizeTwip
.Width(),
276 aSizeTwip
.Height() ) );
277 pTempSet
->Put( SwFormatVertOrient( 0, text::VertOrientation::TOP
, text::RelOrientation::FRAME
));
281 // Resize the frame to the picture size if there is an OLE object
282 // in the frame (only if auto-width)
283 m_pSFlyPara
->BoxUpWidth( aSizeTwip
.Width() );
287 if (pRet
) // OLE object was inserted
289 if (dynamic_cast< const SdrOle2Obj
*>( pRet
) != nullptr)
291 pFormat
= InsertOle(*static_cast<SdrOle2Obj
*>(pRet
), *pFlySet
, pGrfSet
);
292 SdrObject::Free( pRet
); // we don't need this anymore
295 pFormat
= m_rDoc
.getIDocumentContentOperations().InsertDrawObj(*m_pPaM
, *pRet
, *pFlySet
);
298 GraphicType::GdiMetafile
== aGraph
.GetType() ||
299 GraphicType::Bitmap
== aGraph
.GetType()
302 pFormat
= m_rDoc
.getIDocumentContentOperations().Insert(*m_pPaM
, OUString(), OUString(), &aGraph
, pFlySet
,
309 bool SwWW8ImplReader::ImportOleWMF(tools::SvRef
<SotStorage
> xSrc1
,GDIMetaFile
&rWMF
,
314 if( SwWw6ReadMetaStream( rWMF
, &aMfp
, xSrc1
) )
316 // take scaling factor as found in PIC and apply it to graphic.
317 SwWw8ReadScaling( rX
, rY
, xSrc1
);
318 Size aFinalSize
, aOrigSize
;
319 aFinalSize
.Width() = rX
;
320 aFinalSize
.Height() = rY
;
321 aFinalSize
= OutputDevice::LogicToLogic(
322 aFinalSize
, MapUnit::MapTwip
, rWMF
.GetPrefMapMode() );
323 aOrigSize
= rWMF
.GetPrefSize();
324 Fraction
aScaleX(aFinalSize
.Width(),aOrigSize
.Width());
325 Fraction
aScaleY(aFinalSize
.Height(),aOrigSize
.Height());
326 rWMF
.Scale( aScaleX
, aScaleY
);
332 SdrObject
* SwWW8ImplReader::ImportOleBase( Graphic
& rGraph
,
333 const Graphic
* pGrf
, const SfxItemSet
* pFlySet
, const Rectangle
& aVisArea
)
337 SAL_WARN("sw.ww8", "no storage for ole objects");
341 ::SetProgressState( m_nProgress
, m_rDoc
.GetDocShell() ); // Update
343 long nX
=0, nY
=0; // nX, nY is graphic size
346 OUString
aSrcStgName('_');
347 // results in the name "_4711"
348 aSrcStgName
+= OUString::number( m_nObjLocFc
);
350 tools::SvRef
<SotStorage
> xSrc0
= m_pStg
->OpenSotStorage(OUString(SL::aObjectPool
));
351 tools::SvRef
<SotStorage
> xSrc1
= xSrc0
->OpenSotStorage( aSrcStgName
);
356 const Size aSizeTwip
= OutputDevice::LogicToLogic(
357 rGraph
.GetPrefSize(), rGraph
.GetPrefMapMode(), MapUnit::MapTwip
);
358 nX
= aSizeTwip
.Width();
359 nY
= aSizeTwip
.Height();
365 if (ImportOleWMF(xSrc1
,aWMF
,nX
,nY
))
366 rGraph
= Graphic( aWMF
);
367 else if( SwWw6ReadMacPICTStream( rGraph
, xSrc1
) )
369 // 03-META stream is not available. Maybe it's a 03-PICT?
370 const Size aSizeTwip
= OutputDevice::LogicToLogic(
371 rGraph
.GetPrefSize(), rGraph
.GetPrefMapMode(), MapUnit::MapTwip
);
372 nX
= aSizeTwip
.Width();
373 nY
= aSizeTwip
.Height();
374 // PICT: no WMF available -> Graphic instead of OLE
377 } // StorageStreams closed again
379 Rectangle
aRect(0, 0, nX
, nY
);
383 if (const SwFormatFrameSize
* pSize
=
384 static_cast<const SwFormatFrameSize
*>(pFlySet
->GetItem(RES_FRM_SIZE
, false)))
386 aRect
.SetSize(pSize
->GetSize());
390 SdrObject
* pRet
= nullptr;
392 if (!(m_bIsHeader
|| m_bIsFooter
))
394 //Can't put them in headers/footers :-(
395 uno::Reference
< drawing::XShape
> xRef
;
396 OSL_ENSURE(m_pFormImpl
, "Impossible");
397 if (m_pFormImpl
&& m_pFormImpl
->ReadOCXStream(xSrc1
, &xRef
))
399 pRet
= GetSdrObjectFromXShape(xRef
);
400 OSL_ENSURE(pRet
, "Impossible");
402 pRet
->SetLogicRect(aRect
);
407 if (GraphicType::GdiMetafile
== rGraph
.GetType() ||
408 GraphicType::Bitmap
== rGraph
.GetType())
410 ::SetProgressState(m_nProgress
, m_pDocShell
); // Update
414 sal_uLong nOldPos
= m_pDataStream
->Tell();
415 m_pDataStream
->Seek(STREAM_SEEK_TO_END
);
416 SvStream
*pTmpData
= nullptr;
417 if (m_nObjLocFc
< m_pDataStream
->Tell())
419 pTmpData
= m_pDataStream
;
420 pTmpData
->Seek( m_nObjLocFc
);
423 sal_Int64 nAspect
= embed::Aspects::MSOLE_CONTENT
;
426 tools::SvRef
<SotStorageStream
> xObjInfoSrc
= xSrc1
->OpenSotStream("\3ObjInfo",
427 StreamMode::STD_READ
);
428 if ( xObjInfoSrc
.Is() && !xObjInfoSrc
->GetError() )
431 xObjInfoSrc
->ReadUChar( nByte
);
432 if ( ( nByte
>> 4 ) & embed::Aspects::MSOLE_ICON
)
433 nAspect
= embed::Aspects::MSOLE_ICON
;
437 ErrCode nError
= ERRCODE_NONE
;
438 pRet
= SvxMSDffManager::CreateSdrOLEFromStorage(
439 aSrcStgName
, xSrc0
, m_pDocShell
->GetStorage(), rGraph
, aRect
, aVisArea
, pTmpData
, nError
,
440 SwMSDffManager::GetFilterFlags(), nAspect
, GetBaseURL());
441 m_pDataStream
->Seek( nOldPos
);
447 void SwWW8ImplReader::ReadRevMarkAuthorStrTabl( SvStream
& rStrm
,
448 sal_Int32 nTablePos
, sal_Int32 nTableSiz
, SwDoc
& rDocOut
)
450 std::vector
<OUString
> aAuthorNames
;
451 WW8ReadSTTBF( !m_bVer67
, rStrm
, nTablePos
, nTableSiz
, m_bVer67
? 2 : 0,
452 m_eStructCharSet
, aAuthorNames
);
454 sal_uInt16 nCount
= static_cast< sal_uInt16
>(aAuthorNames
.size());
455 for( sal_uInt16 nAuthor
= 0; nAuthor
< nCount
; ++nAuthor
)
457 // Store author in doc
458 sal_uInt16 nSWId
= rDocOut
.getIDocumentRedlineAccess().InsertRedlineAuthor(aAuthorNames
[nAuthor
]);
460 m_aAuthorInfos
[nAuthor
] = nSWId
;
465 Revision Marks ( == Redlining )
467 // insert or delete content (change char attributes resp.)
468 void SwWW8ImplReader::Read_CRevisionMark(RedlineType_t eType
,
469 const sal_uInt8
* pData
, short nLen
)
471 // there *must* be a SprmCIbstRMark[Del] and a SprmCDttmRMark[Del]
472 // pointing to the very same char position as our SprmCFRMark[Del]
475 const sal_uInt8
* pSprmCIbstRMark
;
476 const sal_uInt8
* pSprmCDttmRMark
;
477 if( nsRedlineType_t::REDLINE_FORMAT
== eType
)
479 pSprmCIbstRMark
= nLen
>= 3 ? pData
+1 : nullptr;
480 pSprmCDttmRMark
= nLen
>= 7 ? pData
+3 : nullptr;
484 /* It is possible to have a number of date stamps for the created time
485 * of the change, (possibly a word bug) so we must use the "get a full
486 * list" variant of HasCharSprm and take the last one as the true one.
488 std::vector
<const sal_uInt8
*> aResult
;
489 bool bIns
= (nsRedlineType_t::REDLINE_INSERT
== eType
);
492 m_pPlcxMan
->HasCharSprm(69, aResult
);
493 pSprmCIbstRMark
= aResult
.empty() ? nullptr : aResult
.back();
495 m_pPlcxMan
->HasCharSprm(70, aResult
);
496 pSprmCDttmRMark
= aResult
.empty() ? nullptr : aResult
.back();
500 m_pPlcxMan
->HasCharSprm( bIns
? 0x4804 : 0x4863, aResult
);
501 pSprmCIbstRMark
= aResult
.empty() ? nullptr : aResult
.back();
503 m_pPlcxMan
->HasCharSprm( bIns
? 0x6805 : NS_sprm::LN_CDttmRMarkDel
, aResult
);
504 pSprmCDttmRMark
= aResult
.empty() ? nullptr : aResult
.back();
509 m_pRedlineStack
->close(*m_pPaM
->GetPoint(), eType
, m_pTableDesc
);
512 // start of new revision mark, if not there default to first entry
513 sal_uInt16 nWWAutNo
= pSprmCIbstRMark
? SVBT16ToShort(pSprmCIbstRMark
) : 0;
514 sal_uInt32 nWWDate
= pSprmCDttmRMark
? SVBT32ToUInt32(pSprmCDttmRMark
): 0;
515 DateTime
aStamp(msfilter::util::DTTM2DateTime(nWWDate
));
516 sal_uInt16 nAuthorNo
= m_aAuthorInfos
[nWWAutNo
];
517 SwFltRedline
aNewAttr(eType
, nAuthorNo
, aStamp
);
522 // insert new content
523 void SwWW8ImplReader::Read_CFRMark(sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
525 Read_CRevisionMark( nsRedlineType_t::REDLINE_INSERT
, pData
, nLen
);
528 // delete old content
529 void SwWW8ImplReader::Read_CFRMarkDel(sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
531 Read_CRevisionMark( nsRedlineType_t::REDLINE_DELETE
, pData
, nLen
);
534 // change properties of content ( == char formatting)
535 void SwWW8ImplReader::Read_CPropRMark(sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
537 // complex (len is always 7)
538 // 1 byte - chp.fPropRMark
539 // 2 bytes - chp.ibstPropRMark
540 // 4 bytes - chp.dttmPropRMark;
541 Read_CRevisionMark( nsRedlineType_t::REDLINE_FORMAT
, pData
, nLen
);
544 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */