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 "writerhelper.hxx"
22 #include <com/sun/star/embed/XClassifiedObject.hpp>
23 #include <com/sun/star/embed/Aspects.hpp>
27 #include <osl/endian.h>
28 #include <sot/storage.hxx>
29 #include <com/sun/star/drawing/XShape.hpp>
30 #include <hintids.hxx>
31 #include <svx/svdoole2.hxx>
32 #include <filter/msfilter/msdffimp.hxx>
33 #include <svx/unoapi.hxx>
35 #include <sot/exchange.hxx>
36 #include <swtypes.hxx>
37 #include <fmtanchr.hxx>
38 #include <fmtcntnt.hxx>
39 #include <dcontact.hxx>
43 #include <docsh.hxx> // fuer Ole-Node
44 #include <mdiexp.hxx> // Progress
45 #include <redline.hxx>
46 #include <fltshell.hxx>
47 #include <unodraw.hxx>
48 #include <shellio.hxx>
51 #include <vcl/graphicfilter.hxx>
52 #include <vcl/wmf.hxx>
54 #include "ww8scan.hxx"
56 #include "ww8par2.hxx" // WWFlyPara::BoxUpWidth()
60 sal_Int16 mm
; // 0x6 int
61 sal_Int16 xExt
; // 0x8 int in 1/100 mm
62 sal_Int16 yExt
; // 0xa int in 1/100 mm
63 sal_Int16 hMF
; // 0xc int
66 using namespace ::com::sun::star
;
68 static bool SwWw8ReadScaling(long& rX
, long& rY
, SvStorageRef
& rSrc1
)
70 // Skalierungsfaktoren holen:
71 // Informationen in PIC-Stream ( durch ausprobieren )
73 // 0x08 .. 0x0a Flags ??
76 // 0x0a Inh: immer 8, MAP_ANISOTROPIC ???
78 // 0x0c, 0x10 Originalgroesse x,y in 1/100 mm
79 // 0x14, 0x16 Originalgroesse x,y in tw
80 // 0x2c, 0x30 Skalierung x,y in Promille
81 // 0x34, 0x38, 0x3c, 0x40 Crop Left, Top, Right, Bot in tw
83 SvStorageStreamRef xSrc3
= rSrc1
->OpenSotStream( OUString("\3PIC"),
84 STREAM_STD_READ
| STREAM_NOCREATE
);
85 SvStorageStream
* pS
= xSrc3
;
86 pS
->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
87 pS
->Seek( STREAM_SEEK_TO_END
);
89 OSL_ENSURE( pS
->Tell() >= 76, "+OLE-PIC-Stream is shorter than 76 Byte" );
100 *pS
>> nOrgWidth
// Original Size in 1/100 mm
103 *pS
>> nScaleX
// Scaling in Promille
105 >> nCropLeft
// Cropping in 1/100 mm
110 rX
= nOrgWidth
- nCropLeft
- nCropRight
;
111 rY
= nOrgHeight
- nCropTop
- nCropBottom
;
112 if (10 > nScaleX
|| 65536 < nScaleX
|| 10 > nScaleY
|| 65536 < nScaleY
)
114 OSL_ENSURE( !pS
, "+OLE-Scalinginformation in PIC-Stream wrong" );
119 rX
= (rX
* nScaleX
) / 1000;
120 rY
= (rY
* nScaleY
) / 1000;
125 static bool SwWw6ReadMetaStream(GDIMetaFile
& rWMF
, OLE_MFP
* pMfp
,
128 SvStorageStreamRef xSrc2
= rSrc1
->OpenSotStream( OUString("\3META"),
129 STREAM_STD_READ
| STREAM_NOCREATE
);
130 SvStorageStream
* pSt
= xSrc2
;
131 pSt
->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
132 sal_uLong nRead
= pSt
->Read( pMfp
, sizeof(*pMfp
) );
133 // Mini-Placable-Header lesen
134 if (nRead
!= sizeof(*pMfp
))
137 #if defined OSL_BIGENDIAN
138 pMfp
->mm
= OSL_SWAPWORD( pMfp
->mm
);
139 pMfp
->xExt
= OSL_SWAPWORD( pMfp
->xExt
);
140 pMfp
->yExt
= OSL_SWAPWORD( pMfp
->yExt
);
141 #endif // OSL_BIGENDIAN
143 if( pMfp
->mm
== 94 || pMfp
->mm
== 99 )
145 OSL_ENSURE( !pSt
, "+OLE: Falscher Metafile-Typ" );
150 OSL_ENSURE( !pSt
, "+OLE: Falscher Metafile-Typ ( nicht Anisotropic )" );
152 if( !pMfp
->xExt
|| !pMfp
->yExt
)
154 OSL_ENSURE( !pSt
, "+OLE: Groesse von 0 ???" );
157 bool bOk
= ReadWindowMetafile( *pSt
, rWMF
, NULL
) ? true : false; // WMF lesen
158 // *pSt >> aWMF geht nicht ohne placable Header
159 if (!bOk
|| pSt
->GetError() || rWMF
.GetActionSize() == 0)
161 OSL_ENSURE( !pSt
, "+OLE: Konnte Metafile nicht lesen" );
165 rWMF
.SetPrefMapMode( MapMode( MAP_100TH_MM
) );
168 // MetaFile auf neue Groesse skalieren und
169 // neue Groesse am MetaFile setzen
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
, SvStorageRef
& rSrc1
)
183 // 03-META-Stream nicht da. Vielleicht ein 03-PICT ?
184 SvStorageStreamRef xSrc4
= rSrc1
->OpenSotStream(OUString("\3PICT"));
185 SvStorageStream
* pStp
= xSrc4
;
186 pStp
->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
187 sal_uInt8 aTestA
[10]; // Ist der 01Ole-Stream ueberhaupt vorhanden
188 sal_uLong nReadTst
= pStp
->Read( aTestA
, sizeof( aTestA
) );
189 if (nReadTst
!= sizeof(aTestA
))
192 pStp
->Seek( STREAM_SEEK_TO_BEGIN
);
194 // Mac-Pict steht im 03PICT-StorageStream allerdings ohne die ersten 512
195 // Bytes, die bei einem MAC-PICT egal sind ( werden nicht ausgewertet )
196 return SwWW8ImplReader::GetPictGrafFromStream(rGraph
, *pStp
);
199 SwFlyFrmFmt
* SwWW8ImplReader::InsertOle(SdrOle2Obj
&rObject
,
200 const SfxItemSet
&rFlySet
, const SfxItemSet
&rGrfSet
)
202 SfxObjectShell
*pPersist
= rDoc
.GetPersist();
203 OSL_ENSURE(pPersist
, "No persist, cannot insert objects correctly");
207 SwFlyFrmFmt
*pRet
= 0;
209 SfxItemSet
*pMathFlySet
= 0;
210 uno::Reference
< embed::XClassifiedObject
> xClass( rObject
.GetObjRef(), uno::UNO_QUERY
);
213 SvGlobalName
aClassName( xClass
->getClassID() );
214 if (SotExchange::IsMath(aClassName
))
217 StarMath sets it own fixed size, so its counter productive to use the
218 size word says it is. i.e. Don't attempt to override its size.
220 pMathFlySet
= new SfxItemSet(rFlySet
);
221 pMathFlySet
->ClearItem(RES_FRM_SIZE
);
226 Take complete responsibility of the object away from SdrOle2Obj and to
227 me here locally. This utility class now owns the object.
230 // TODO/MBA: is the object inserted multiple times here? Testing!
231 // And is it a problem that we now use the same naming scheme as in the other apps?
232 sw::hack::DrawingOLEAdaptor
aOLEObj(rObject
, *pPersist
);
234 bool bSuccess
= aOLEObj
.TransferToDoc(sNewName
);
236 OSL_ENSURE(bSuccess
, "Insert OLE failed");
239 const SfxItemSet
*pFlySet
= pMathFlySet
? pMathFlySet
: &rFlySet
;
240 pRet
= rDoc
.InsertOLE(*pPaM
, sNewName
, rObject
.GetAspect(), pFlySet
, &rGrfSet
, 0);
246 SwFrmFmt
* SwWW8ImplReader::ImportOle(const Graphic
* pGrf
,
247 const SfxItemSet
* pFlySet
, const SfxItemSet
*pGrfSet
, const Rectangle
& aVisArea
)
249 ::SetProgressState(nProgress
, mpDocShell
); // Update
255 SdrObject
* pRet
= ImportOleBase(aGraph
, pGrf
, pFlySet
, aVisArea
);
258 SfxItemSet
* pTempSet
= 0;
261 pTempSet
= new SfxItemSet( rDoc
.GetAttrPool(), RES_FRMATR_BEGIN
,
266 // Abstand/Umrandung raus
268 Reader::ResetFrmFmtAttrs( *pTempSet
);
270 SwFmtAnchor
aAnchor( FLY_AS_CHAR
);
271 aAnchor
.SetAnchor( pPaM
->GetPoint() );
272 pTempSet
->Put( aAnchor
);
274 const Size aSizeTwip
= OutputDevice::LogicToLogic(
275 aGraph
.GetPrefSize(), aGraph
.GetPrefMapMode(), MAP_TWIP
);
277 pTempSet
->Put( SwFmtFrmSize( ATT_FIX_SIZE
, aSizeTwip
.Width(),
278 aSizeTwip
.Height() ) );
279 pTempSet
->Put( SwFmtVertOrient( 0, text::VertOrientation::TOP
, text::RelOrientation::FRAME
));
283 // OLE im Rahmen ? ok, Rahmen auf Bildgroesse vergroessern (
284 // nur wenn Auto-Breite )
285 pSFlyPara
->BoxUpWidth( aSizeTwip
.Width() );
289 if (pRet
) // Ole-Object wurde eingefuegt
291 if (pRet
->ISA(SdrOle2Obj
))
293 pFmt
= InsertOle(*((SdrOle2Obj
*)pRet
), *pFlySet
, *pGrfSet
);
294 SdrObject::Free( pRet
); // das brauchen wir nicht mehr
297 pFmt
= rDoc
.Insert(*pPaM
, *pRet
, pFlySet
, NULL
);
300 GRAPHIC_GDIMETAFILE
== aGraph
.GetType() ||
301 GRAPHIC_BITMAP
== aGraph
.GetType()
304 pFmt
= rDoc
.Insert(*pPaM
, aEmptyStr
, aEmptyStr
, &aGraph
, pFlySet
,
311 bool SwWW8ImplReader::ImportOleWMF(SvStorageRef xSrc1
,GDIMetaFile
&rWMF
,
316 if( SwWw6ReadMetaStream( rWMF
, &aMfp
, xSrc1
) )
319 take scaling factor as found in PIC and apply it to graphic.
321 SwWw8ReadScaling( rX
, rY
, xSrc1
);
322 Size aFinalSize
, aOrigSize
;
323 aFinalSize
.Width() = rX
;
324 aFinalSize
.Height() = rY
;
325 aFinalSize
= OutputDevice::LogicToLogic(
326 aFinalSize
, MAP_TWIP
, rWMF
.GetPrefMapMode() );
327 aOrigSize
= rWMF
.GetPrefSize();
328 Fraction
aScaleX(aFinalSize
.Width(),aOrigSize
.Width());
329 Fraction
aScaleY(aFinalSize
.Height(),aOrigSize
.Height());
330 rWMF
.Scale( aScaleX
, aScaleY
);
336 SdrObject
* SwWW8ImplReader::ImportOleBase( Graphic
& rGraph
,
337 const Graphic
* pGrf
, const SfxItemSet
* pFlySet
, const Rectangle
& aVisArea
)
340 OSL_ENSURE( pStg
, "ohne storage geht hier fast gar nichts!" );
342 ::SetProgressState( nProgress
, rDoc
.GetDocShell() ); // Update
344 long nX
=0, nY
=0; // nX, nY is graphic size
347 String aSrcStgName
= OUString('_');
348 // ergibt Name "_4711"
349 aSrcStgName
+= OUString::number( nObjLocFc
);
351 SvStorageRef xSrc0
= pStg
->OpenSotStorage(OUString(SL::aObjectPool
));
352 SvStorageRef xSrc1
= xSrc0
->OpenSotStorage( aSrcStgName
,
353 STREAM_READWRITE
| STREAM_SHARE_DENYALL
);
359 const Size aSizeTwip
= OutputDevice::LogicToLogic(
360 rGraph
.GetPrefSize(), rGraph
.GetPrefMapMode(), MAP_TWIP
);
361 nX
= aSizeTwip
.Width();
362 nY
= aSizeTwip
.Height();
368 if (ImportOleWMF(xSrc1
,aWMF
,nX
,nY
))
369 rGraph
= Graphic( aWMF
);
370 else if( SwWw6ReadMacPICTStream( rGraph
, xSrc1
) )
372 // 03-META-Stream nicht da. Vielleicht ein 03-PICT ?
373 const Size aSizeTwip
= OutputDevice::LogicToLogic(
374 rGraph
.GetPrefSize(), rGraph
.GetPrefMapMode(), MAP_TWIP
);
375 nX
= aSizeTwip
.Width();
376 nY
= aSizeTwip
.Height();
377 // PICT: kein WMF da -> Grafik statt OLE
380 } // StorageStreams wieder zu
383 Rectangle
aRect(0, 0, nX
, nY
);
387 if (const SwFmtFrmSize
* pSize
=
388 (const SwFmtFrmSize
*)pFlySet
->GetItem(RES_FRM_SIZE
, false))
390 aRect
.SetSize(pSize
->GetSize());
394 if (!(bIsHeader
|| bIsFooter
))
396 //Can't put them in headers/footers :-(
397 uno::Reference
< drawing::XShape
> xRef
;
398 OSL_ENSURE(pFormImpl
, "Impossible");
399 if (pFormImpl
&& pFormImpl
->ReadOCXStream(xSrc1
, &xRef
, false))
401 pRet
= GetSdrObjectFromXShape(xRef
);
402 OSL_ENSURE(pRet
, "Impossible");
404 pRet
->SetLogicRect(aRect
);
409 if (GRAPHIC_GDIMETAFILE
== rGraph
.GetType() ||
410 GRAPHIC_BITMAP
== rGraph
.GetType())
412 ::SetProgressState(nProgress
, mpDocShell
); // Update
416 sal_uLong nOldPos
= pDataStream
->Tell();
417 pDataStream
->Seek(STREAM_SEEK_TO_END
);
418 SvStream
*pTmpData
= 0;
419 if (nObjLocFc
< pDataStream
->Tell())
421 pTmpData
= pDataStream
;
422 pTmpData
->Seek( nObjLocFc
);
425 sal_Int64 nAspect
= embed::Aspects::MSOLE_CONTENT
;
428 SvStorageStreamRef xObjInfoSrc
= xSrc1
->OpenSotStream(OUString("\3ObjInfo"),
429 STREAM_STD_READ
| STREAM_NOCREATE
);
430 if ( xObjInfoSrc
.Is() && !xObjInfoSrc
->GetError() )
433 *xObjInfoSrc
>> nByte
;
434 if ( ( nByte
>> 4 ) & embed::Aspects::MSOLE_ICON
)
435 nAspect
= embed::Aspects::MSOLE_ICON
;
439 ErrCode nError
= ERRCODE_NONE
;
440 pRet
= SvxMSDffManager::CreateSdrOLEFromStorage(
441 aSrcStgName
, xSrc0
, mpDocShell
->GetStorage(), rGraph
, aRect
, aVisArea
, pTmpData
, nError
,
442 SwMSDffManager::GetFilterFlags(), nAspect
);
443 pDataStream
->Seek( nOldPos
);
449 void SwWW8ImplReader::ReadRevMarkAuthorStrTabl( SvStream
& rStrm
,
450 sal_Int32 nTblPos
, sal_Int32 nTblSiz
, SwDoc
& rDocOut
)
452 ::std::vector
<String
> aAuthorNames
;
453 WW8ReadSTTBF( !bVer67
, rStrm
, nTblPos
, nTblSiz
, bVer67
? 2 : 0,
454 eStructCharSet
, aAuthorNames
);
456 sal_uInt16 nCount
= static_cast< sal_uInt16
>(aAuthorNames
.size());
457 for( sal_uInt16 nAuthor
= 0; nAuthor
< nCount
; ++nAuthor
)
459 // Store author in doc
460 sal_uInt16 nSWId
= rDocOut
.InsertRedlineAuthor(aAuthorNames
[nAuthor
]);
462 m_aAuthorInfos
[nAuthor
] = nSWId
;
467 Revision Marks ( == Redlining )
469 // insert or delete content (change char attributes resp.)
470 void SwWW8ImplReader::Read_CRevisionMark(RedlineType_t eType
,
471 const sal_uInt8
* pData
, short nLen
)
473 // there *must* be a SprmCIbstRMark[Del] and a SprmCDttmRMark[Del]
474 // pointing to the very same char position as our SprmCFRMark[Del]
477 const sal_uInt8
* pSprmCIbstRMark
;
478 const sal_uInt8
* pSprmCDttmRMark
;
479 if( nsRedlineType_t::REDLINE_FORMAT
== eType
)
481 pSprmCIbstRMark
= pData
+1;
482 pSprmCDttmRMark
= pData
+3;
487 It is possible to have a number of date stamps for the created time
488 of the change, (possibly a word bug) so we must use the "get a full
489 list" varient of HasCharSprm and take the last one as the true one.
491 std::vector
<const sal_uInt8
*> aResult
;
492 bool bIns
= (nsRedlineType_t::REDLINE_INSERT
== eType
);
495 pPlcxMan
->HasCharSprm(69, aResult
);
496 pSprmCIbstRMark
= aResult
.empty() ? 0 : aResult
.back();
498 pPlcxMan
->HasCharSprm(70, aResult
);
499 pSprmCDttmRMark
= aResult
.empty() ? 0 : aResult
.back();
503 pPlcxMan
->HasCharSprm( bIns
? 0x4804 : 0x4863, aResult
);
504 pSprmCIbstRMark
= aResult
.empty() ? 0 : aResult
.back();
506 pPlcxMan
->HasCharSprm( bIns
? 0x6805 : 0x6864, aResult
);
507 pSprmCDttmRMark
= aResult
.empty() ? 0 : aResult
.back();
512 mpRedlineStack
->close(*pPaM
->GetPoint(), eType
, pTableDesc
);
515 // start of new revision mark, if not there default to first entry
516 sal_uInt16 nWWAutNo
= pSprmCIbstRMark
? SVBT16ToShort(pSprmCIbstRMark
) : 0;
517 sal_uInt32 nWWDate
= pSprmCDttmRMark
? SVBT32ToUInt32(pSprmCDttmRMark
): 0;
518 DateTime
aStamp(msfilter::util::DTTM2DateTime(nWWDate
));
519 sal_uInt16 nAuthorNo
= m_aAuthorInfos
[nWWAutNo
];
520 SwFltRedline
aNewAttr(eType
, nAuthorNo
, aStamp
);
525 // insert new content
526 void SwWW8ImplReader::Read_CFRMark(sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
528 Read_CRevisionMark( nsRedlineType_t::REDLINE_INSERT
, pData
, nLen
);
531 // delete old content
532 void SwWW8ImplReader::Read_CFRMarkDel(sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
534 Read_CRevisionMark( nsRedlineType_t::REDLINE_DELETE
, pData
, nLen
);
537 // change properties of content ( == char formating)
538 void SwWW8ImplReader::Read_CPropRMark(sal_uInt16
, const sal_uInt8
* pData
, short nLen
)
540 // complex (len is always 7)
541 // 1 byte - chp.fPropRMark
542 // 2 bytes - chp.ibstPropRMark
543 // 4 bytes - chp.dttmPropRMark;
544 Read_CRevisionMark( nsRedlineType_t::REDLINE_FORMAT
, pData
, nLen
);
547 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */