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 .
20 #include <hintids.hxx>
21 #include <i18nlangtag/lang.h>
22 #include <i18nlangtag/languagetag.hxx>
23 #include <o3tl/any.hxx>
24 #include <tools/svlibrary.h>
25 #include <sot/storage.hxx>
26 #include <shellio.hxx>
29 #include <fmtfsize.hxx>
30 #include <swtable.hxx>
31 #include <fmtcntnt.hxx>
32 #include <editeng/boxitem.hxx>
34 #include <swfltopt.hxx>
36 #include <iodetect.hxx>
37 #include <osl/module.hxx>
38 #include <rtl/bootstrap.hxx>
39 #include <sal/log.hxx>
40 #include <osl/diagnose.h>
43 using namespace com::sun::star::uno
;
44 using namespace com::sun::star
;
46 Reader
*ReadAscii
= nullptr, *ReadHTML
= nullptr, *ReadXML
= nullptr;
48 static Reader
* GetRTFReader();
49 static Reader
* GetWW8Reader();
50 static Reader
* GetDOCXReader();
52 // Note: if editing, please don't forget to modify also the enum
53 // ReaderWriterEnum and aFilterDetect in iodetect.hxx & iodetect.cxx
54 static SwReaderWriterEntry aReaderWriter
[] =
56 SwReaderWriterEntry( &::GetRTFReader
, &::GetRTFWriter
, true ),
57 SwReaderWriterEntry( nullptr, &::GetASCWriter
, false ),
58 SwReaderWriterEntry( &::GetWW8Reader
, nullptr, true ),
59 SwReaderWriterEntry( &::GetWW8Reader
, &::GetWW8Writer
, true ),
60 SwReaderWriterEntry( &::GetRTFReader
, &::GetRTFWriter
, true ),
61 SwReaderWriterEntry( nullptr, &::GetHTMLWriter
, true ),
62 SwReaderWriterEntry( &::GetWW8Reader
, nullptr, true ),
63 SwReaderWriterEntry( nullptr, &::GetXMLWriter
, true ),
64 SwReaderWriterEntry( nullptr, &::GetASCWriter
, false ),
65 SwReaderWriterEntry( nullptr, &::GetASCWriter
, true ),
66 SwReaderWriterEntry( &::GetDOCXReader
, nullptr, true )
69 Reader
* SwReaderWriterEntry::GetReader()
73 else if ( fnGetReader
)
75 pReader
= (*fnGetReader
)();
81 void SwReaderWriterEntry::GetWriter( std::u16string_view rNm
, const OUString
& rBaseURL
, WriterRef
& xWrt
) const
84 (*fnGetWriter
)( rNm
, rBaseURL
, xWrt
);
86 xWrt
= WriterRef(nullptr);
89 Reader
* SwGetReaderXML() // SW_DLLPUBLIC
94 static void SetFltPtr( sal_uInt16 rPos
, Reader
* pReader
)
96 aReaderWriter
[ rPos
].pReader
= pReader
;
103 ReadAscii
= new AsciiReader
;
104 ReadHTML
= new HTMLReader
;
105 ReadXML
= new XMLReader
;
106 SetFltPtr( READER_WRITER_BAS
, ReadAscii
);
107 SetFltPtr( READER_WRITER_HTML
, ReadHTML
);
108 SetFltPtr( READER_WRITER_XML
, ReadXML
);
109 SetFltPtr( READER_WRITER_TEXT_DLG
, ReadAscii
);
110 SetFltPtr( READER_WRITER_TEXT
, ReadAscii
);
116 for(SwReaderWriterEntry
& rEntry
: aReaderWriter
)
118 if( rEntry
.bDelReader
&& rEntry
.pReader
)
120 delete rEntry
.pReader
;
121 rEntry
.pReader
= nullptr;
127 #ifndef DISABLE_DYNLOADING
129 oslGenericFunction
Filters::GetMswordLibSymbol( const char *pSymbol
)
133 OUString
url("$LO_LIB_DIR/" SVLIBRARY("msword"));
134 rtl::Bootstrap::expandMacros(url
);
135 bool ok
= msword_
.load( url
, SAL_LOADMODULE_GLOBAL
| SAL_LOADMODULE_LAZY
);
136 SAL_WARN_IF(!ok
, "sw", "failed to load msword library");
139 return msword_
.getFunctionSymbol( OUString::createFromAscii( pSymbol
) );
147 namespace SwReaderWriter
{
149 Reader
* GetRtfReader()
151 return aReaderWriter
[READER_WRITER_RTF
].GetReader();
154 Reader
* GetDOCXReader()
156 return aReaderWriter
[READER_WRITER_DOCX
].GetReader();
159 void GetWriter( std::u16string_view rFltName
, const OUString
& rBaseURL
, WriterRef
& xRet
)
161 for( int n
= 0; n
< MAXFILTER
; ++n
)
162 if ( aFilterDetect
[n
].IsFilter( rFltName
) )
164 aReaderWriter
[n
].GetWriter( rFltName
, rBaseURL
, xRet
);
169 Reader
* GetReader( const OUString
& rFltName
)
171 Reader
* pRead
= nullptr;
172 for( int n
= 0; n
< MAXFILTER
; ++n
)
174 if ( aFilterDetect
[n
].IsFilter( rFltName
) )
176 pRead
= aReaderWriter
[n
].GetReader();
177 // add special treatment for some readers
179 pRead
->SetFltName( rFltName
);
186 } // namespace SwReaderWriter
188 bool Writer::IsStgWriter() const { return false; }
190 bool StgWriter::IsStgWriter() const { return true; }
192 // Read Filter Flags; used by WW8 / W4W / EXCEL / LOTUS
197 <WW1F cfg:type="long">0</WW1F>
198 <WW cfg:type="long">0</WW>
199 <WW8 cfg:type="long">0</WW8>
200 <WWF cfg:type="long">0</WWF>
201 <WWFA0 cfg:type="long">0</WWFA0>
202 <WWFA1 cfg:type="long">0</WWFA1>
203 <WWFA2 cfg:type="long">0</WWFA2>
204 <WWFB0 cfg:type="long">0</WWFB0>
205 <WWFB1 cfg:type="long">0</WWFB1>
206 <WWFB2 cfg:type="long">0</WWFB2>
207 <WWFLX cfg:type="long">0</WWFLX>
208 <WWFLY cfg:type="long">0</WWFLY>
209 <WWFT cfg:type="long">0</WWFT>
210 <WWWR cfg:type="long">0</WWWR>
215 SwFilterOptions::SwFilterOptions( sal_uInt16 nCnt
, const char** ppNames
,
216 sal_uInt64
* pValues
)
217 : ConfigItem( "Office.Writer/FilterFlags" )
219 GetValues( nCnt
, ppNames
, pValues
);
222 void SwFilterOptions::GetValues( sal_uInt16 nCnt
, const char** ppNames
,
223 sal_uInt64
* pValues
)
225 Sequence
<OUString
> aNames( nCnt
);
226 OUString
* pNames
= aNames
.getArray();
229 for( n
= 0; n
< nCnt
; ++n
)
230 pNames
[ n
] = OUString::createFromAscii( ppNames
[ n
] );
231 Sequence
<Any
> aValues
= GetProperties( aNames
);
233 if( nCnt
== aValues
.getLength() )
235 const Any
* pAnyValues
= aValues
.getConstArray();
236 for( n
= 0; n
< nCnt
; ++n
)
237 pValues
[ n
] = pAnyValues
[ n
].hasValue()
238 ? *o3tl::doAccess
<sal_uInt64
>(pAnyValues
[ n
])
243 for( n
= 0; n
< nCnt
; ++n
)
248 void SwFilterOptions::ImplCommit() {}
249 void SwFilterOptions::Notify( const css::uno::Sequence
< OUString
>& ) {}
251 void StgReader::SetFltName( const OUString
& rFltNm
)
253 if( SwReaderType::Storage
& GetReaderType() )
257 void CalculateFlySize(SfxItemSet
& rFlySet
, const SwNode
& rAnchor
,
260 const SwFormatFrameSize
* pFrameSizeItem
= rFlySet
.GetItemIfSet( RES_FRM_SIZE
);
261 if( !pFrameSizeItem
|| MINFLY
> pFrameSizeItem
->GetWidth() )
263 std::unique_ptr
<SwFormatFrameSize
> aSz(rFlySet
.Get(RES_FRM_SIZE
).Clone());
265 aSz
.reset(pFrameSizeItem
->Clone());
268 // determine the width; if there is a table use the width of the table;
269 // otherwise use the width of the page
270 const SwTableNode
* pTableNd
= rAnchor
.FindTableNode();
272 nWidth
= pTableNd
->GetTable().GetFrameFormat()->GetFrameSize().GetWidth();
276 const SwNodeIndex
* pSttNd
= rFlySet
.Get( RES_CNTNT
).GetContentIdx();
279 bool bOnlyOneNode
= true;
280 sal_uLong nMinFrame
= 0;
281 sal_uLong nMaxFrame
= 0;
282 SwTextNode
* pFirstTextNd
= nullptr;
283 SwNodeIndex
aIdx( *pSttNd
, 1 );
284 SwNodeIndex
aEnd( *pSttNd
->GetNode().EndOfSectionNode() );
287 SwTextNode
*pTextNd
= aIdx
.GetNode().GetTextNode();
291 pFirstTextNd
= pTextNd
;
292 else if( pFirstTextNd
!= pTextNd
)
295 bOnlyOneNode
= false;
299 sal_uLong nAbsMinCnts
;
300 pTextNd
->GetMinMaxSize( aIdx
.GetIndex(), nMinFrame
, nMaxFrame
, nAbsMinCnts
);
307 if( nMinFrame
< MINLAY
&& pFirstTextNd
)
309 // if the first node don't contained any content, then
310 // insert one char in it calc again and delete once again
311 SwContentIndex
aNdIdx( pFirstTextNd
);
312 pFirstTextNd
->InsertText("MM", aNdIdx
);
313 sal_uLong nAbsMinCnts
;
314 pFirstTextNd
->GetMinMaxSize( pFirstTextNd
->GetIndex(),
315 nMinFrame
, nMaxFrame
, nAbsMinCnts
);
317 pFirstTextNd
->EraseText( aNdIdx
, 2 );
320 // consider border and distance to content
321 const SvxBoxItem
& rBoxItem
= rFlySet
.Get( RES_BOX
);
322 SvxBoxItemLine nLine
= SvxBoxItemLine::LEFT
;
323 for( int i
= 0; i
< 2; ++i
)
325 const editeng::SvxBorderLine
* pLn
= rBoxItem
.GetLine( nLine
);
328 sal_uInt16 nWidthTmp
= pLn
->GetOutWidth() + pLn
->GetInWidth();
329 nWidthTmp
= nWidthTmp
+ rBoxItem
.GetDistance( nLine
);
330 nMinFrame
+= nWidthTmp
;
331 nMaxFrame
+= nWidthTmp
;
333 nLine
= SvxBoxItemLine::RIGHT
;
336 // enforce minimum width for contents
337 if( nMinFrame
< MINLAY
)
339 if( nMaxFrame
< MINLAY
)
342 if( nWidth
> o3tl::narrowing
<sal_uInt16
>(nMaxFrame
) )
344 else if( nWidth
> o3tl::narrowing
<sal_uInt16
>(nMinFrame
) )
349 if( MINFLY
> nWidth
)
352 aSz
->SetWidth( nWidth
);
353 if( MINFLY
> aSz
->GetHeight() )
354 aSz
->SetHeight( MINFLY
);
355 rFlySet
.Put( std::move(aSz
) );
357 else if( MINFLY
> pFrameSizeItem
->GetHeight() )
359 std::unique_ptr
<SwFormatFrameSize
> aSz(pFrameSizeItem
->Clone());
360 aSz
->SetHeight( MINFLY
);
361 rFlySet
.Put( std::move(aSz
) );
368 struct CharSetNameMap
370 rtl_TextEncoding eCode
;
374 const CharSetNameMap
*GetCharSetNameMap()
376 static const CharSetNameMap aMapArr
[] =
378 # define IMPLENTRY(X) { RTL_TEXTENCODING_##X, #X }
381 IMPLENTRY(APPLE_ROMAN
),
390 IMPLENTRY(ISO_8859_1
),
391 IMPLENTRY(ISO_8859_2
),
392 IMPLENTRY(ISO_8859_3
),
393 IMPLENTRY(ISO_8859_4
),
394 IMPLENTRY(ISO_8859_5
),
395 IMPLENTRY(ISO_8859_6
),
396 IMPLENTRY(ISO_8859_7
),
397 IMPLENTRY(ISO_8859_8
),
398 IMPLENTRY(ISO_8859_9
),
399 IMPLENTRY(ISO_8859_14
),
400 IMPLENTRY(ISO_8859_15
),
419 IMPLENTRY(APPLE_ARABIC
),
420 IMPLENTRY(APPLE_CENTEURO
),
421 IMPLENTRY(APPLE_CROATIAN
),
422 IMPLENTRY(APPLE_CYRILLIC
),
423 IMPLENTRY(APPLE_DEVANAGARI
),
424 IMPLENTRY(APPLE_FARSI
),
425 IMPLENTRY(APPLE_GREEK
),
426 IMPLENTRY(APPLE_GUJARATI
),
427 IMPLENTRY(APPLE_GURMUKHI
),
428 IMPLENTRY(APPLE_HEBREW
),
429 IMPLENTRY(APPLE_ICELAND
),
430 IMPLENTRY(APPLE_ROMANIAN
),
431 IMPLENTRY(APPLE_THAI
),
432 IMPLENTRY(APPLE_TURKISH
),
433 IMPLENTRY(APPLE_UKRAINIAN
),
434 IMPLENTRY(APPLE_CHINSIMP
),
435 IMPLENTRY(APPLE_CHINTRAD
),
436 IMPLENTRY(APPLE_JAPANESE
),
437 IMPLENTRY(APPLE_KOREAN
),
442 IMPLENTRY(SHIFT_JIS
),
444 IMPLENTRY(GBT_12345
),
450 IMPLENTRY(ISO_2022_JP
),
451 IMPLENTRY(ISO_2022_CN
),
456 IMPLENTRY(ISO_8859_10
),
457 IMPLENTRY(ISO_8859_13
),
459 IMPLENTRY(ISO_2022_KR
),
460 IMPLENTRY(JIS_X_0201
),
461 IMPLENTRY(JIS_X_0208
),
462 IMPLENTRY(JIS_X_0212
),
465 IMPLENTRY(BIG5_HKSCS
),
477 Get a rtl_TextEncoding from its name
479 rtl_TextEncoding
CharSetFromName(std::u16string_view rChrSetStr
)
481 const CharSetNameMap
*pStart
= GetCharSetNameMap();
482 rtl_TextEncoding nRet
= pStart
->eCode
;
484 for(const CharSetNameMap
*pMap
= pStart
; pMap
->pName
; ++pMap
)
486 if(o3tl::equalsIgnoreAsciiCase(rChrSetStr
, pMap
->pName
))
493 OSL_ENSURE(nRet
!= pStart
->eCode
, "TXT: That was an unknown language!");
499 Get the String name of an rtl_TextEncoding
501 OUString
NameFromCharSet(rtl_TextEncoding nChrSet
)
503 const CharSetNameMap
*pStart
= GetCharSetNameMap();
504 const char *pRet
= pStart
->pName
;
506 for(const CharSetNameMap
*pMap
= pStart
; pMap
->pName
; ++pMap
)
508 if (nChrSet
== pMap
->eCode
)
515 OSL_ENSURE(pRet
!= pStart
->pName
, "TXT: That was an unknown language!");
517 return OUString::createFromAscii(pRet
);
522 // for the automatic conversion (mail/news/...)
523 // The user data contains the options for the ascii import/export filter.
525 // 1. CharSet - as ascii chars
526 // 2. LineEnd - as CR/LF/CRLF
529 // 5. Whether to include byte-order-mark - as true/false
530 // 6. Whether to include hidden paragraphs and text - as true/false
531 // the delimiter character is ","
533 void SwAsciiOptions::ReadUserData( std::u16string_view rStr
)
535 sal_Int32 nToken
= 0;
536 std::u16string_view sToken
= o3tl::getToken(rStr
, 0, ',', nToken
); // 1. Charset name
538 m_eCharSet
= CharSetFromName(sToken
);
539 if (nToken
>= 0 && !(sToken
= o3tl::getToken(rStr
, 0, ',', nToken
)).empty()) // 2. Line ending type
541 if (o3tl::equalsIgnoreAsciiCase(sToken
, u
"CRLF"))
542 m_eCRLF_Flag
= LINEEND_CRLF
;
543 else if (o3tl::equalsIgnoreAsciiCase(sToken
, u
"LF"))
544 m_eCRLF_Flag
= LINEEND_LF
;
546 m_eCRLF_Flag
= LINEEND_CR
;
548 if (nToken
>= 0 && !(sToken
= o3tl::getToken(rStr
, 0, ',', nToken
)).empty()) // 3. Font name
550 if (nToken
>= 0 && !(sToken
= o3tl::getToken(rStr
, 0, ',', nToken
)).empty()) // 4. Language tag
551 m_nLanguage
= LanguageTag::convertToLanguageTypeWithFallback(OUString(sToken
));
552 if (nToken
>= 0 && !(sToken
= o3tl::getToken(rStr
, 0, ',', nToken
)).empty()) // 5. Include BOM?
553 m_bIncludeBOM
= !(o3tl::equalsIgnoreAsciiCase(sToken
, u
"FALSE"));
554 // 6. Include hidden text
555 if (nToken
>= 0 && !(sToken
= o3tl::getToken(rStr
, 0, ',', nToken
)).empty())
556 m_bIncludeHidden
= !(o3tl::equalsIgnoreAsciiCase(sToken
, u
"FALSE"));
559 void SwAsciiOptions::WriteUserData(OUString
& rStr
) const
562 rStr
= NameFromCharSet(m_eCharSet
) + ",";
580 rStr
+= m_sFont
+ ",";
585 rStr
+= LanguageTag::convertToBcp47(m_nLanguage
);
589 // 5. Whether to include byte-order-mark
600 // 6. Whether to include hidden paragraphs and text
612 #ifdef DISABLE_DYNLOADING
616 void ExportRTF( std::u16string_view
, const OUString
& rBaseURL
, WriterRef
& );
618 void ExportDOC( std::u16string_view
, const OUString
& rBaseURL
, WriterRef
& );
619 Reader
*ImportDOCX();
620 sal_uInt32
SaveOrDelMSVBAStorage_ww8( SfxObjectShell
&, SotStorage
&, sal_Bool
, const OUString
& );
621 sal_uInt32
GetSaveWarningOfMSVBAStorage_ww8( SfxObjectShell
& );
626 Reader
* GetRTFReader()
628 #ifndef DISABLE_DYNLOADING
630 FnGetReader pFunction
= reinterpret_cast<FnGetReader
>( SwGlobals::getFilters().GetMswordLibSymbol( "ImportRTF" ) );
633 return (*pFunction
)();
642 void GetRTFWriter( std::u16string_view rFltName
, const OUString
& rBaseURL
, WriterRef
& xRet
)
644 #ifndef DISABLE_DYNLOADING
645 FnGetWriter pFunction
= reinterpret_cast<FnGetWriter
>( SwGlobals::getFilters().GetMswordLibSymbol( "ExportRTF" ) );
648 (*pFunction
)( rFltName
, rBaseURL
, xRet
);
650 xRet
= WriterRef(nullptr);
652 ExportRTF( rFltName
, rBaseURL
, xRet
);
656 Reader
* GetWW8Reader()
658 #ifndef DISABLE_DYNLOADING
659 FnGetReader pFunction
= reinterpret_cast<FnGetReader
>( SwGlobals::getFilters().GetMswordLibSymbol( "ImportDOC" ) );
662 return (*pFunction
)();
670 void GetWW8Writer( std::u16string_view rFltName
, const OUString
& rBaseURL
, WriterRef
& xRet
)
672 #ifndef DISABLE_DYNLOADING
673 FnGetWriter pFunction
= reinterpret_cast<FnGetWriter
>( SwGlobals::getFilters().GetMswordLibSymbol( "ExportDOC" ) );
676 (*pFunction
)( rFltName
, rBaseURL
, xRet
);
678 xRet
= WriterRef(nullptr);
680 ExportDOC( rFltName
, rBaseURL
, xRet
);
684 Reader
* GetDOCXReader()
686 #ifndef DISABLE_DYNLOADING
687 FnGetReader pFunction
= reinterpret_cast<FnGetReader
>( SwGlobals::getFilters().GetMswordLibSymbol( "ImportDOCX" ) );
690 return (*pFunction
)();
698 typedef sal_uInt32 ( *SaveOrDel
)( SfxObjectShell
&, SotStorage
&, sal_Bool
, const OUString
& );
699 typedef sal_uInt32 ( *GetSaveWarning
)( SfxObjectShell
& );
701 ErrCode
SaveOrDelMSVBAStorage( SfxObjectShell
& rDoc
, SotStorage
& rStor
, bool bSaveInto
, const OUString
& rStorageName
)
703 #ifndef DISABLE_DYNLOADING
704 SaveOrDel pFunction
= reinterpret_cast<SaveOrDel
>( SwGlobals::getFilters().GetMswordLibSymbol( "SaveOrDelMSVBAStorage_ww8" ) );
706 return ErrCode(pFunction( rDoc
, rStor
, bSaveInto
, rStorageName
));
709 return ErrCode(SaveOrDelMSVBAStorage_ww8( rDoc
, rStor
, bSaveInto
, rStorageName
));
713 ErrCode
GetSaveWarningOfMSVBAStorage( SfxObjectShell
&rDocS
)
715 #ifndef DISABLE_DYNLOADING
716 GetSaveWarning pFunction
= reinterpret_cast<GetSaveWarning
>( SwGlobals::getFilters().GetMswordLibSymbol( "GetSaveWarningOfMSVBAStorage_ww8" ) );
718 return ErrCode(pFunction( rDocS
));
721 return ErrCode(GetSaveWarningOfMSVBAStorage_ww8( rDocS
));
725 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */