LibreOffice Module sw (master) 1
SwXMLTextBlocks1.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <com/sun/star/embed/ElementModes.hpp>
21#include <com/sun/star/embed/XTransactedObject.hpp>
22#include <osl/diagnose.h>
23#include <svl/macitem.hxx>
24#include <svtools/unoevent.hxx>
25#include <sfx2/docfile.hxx>
29#include <com/sun/star/beans/XPropertySet.hpp>
30#include <com/sun/star/xml/sax/InputSource.hpp>
31#include <com/sun/star/io/IOException.hpp>
32#include <com/sun/star/xml/sax/FastParser.hpp>
33#include <com/sun/star/xml/sax/FastToken.hpp>
34#include <com/sun/star/xml/sax/Parser.hpp>
35#include <com/sun/star/xml/sax/Writer.hpp>
36#include <com/sun/star/xml/sax/SAXParseException.hpp>
37#include <com/sun/star/document/XStorageBasedDocument.hpp>
38#include <doc.hxx>
39#include <docsh.hxx>
40#include <shellio.hxx>
41#include <SwXMLTextBlocks.hxx>
42#include <SwXMLBlockImport.hxx>
43#include <SwXMLBlockExport.hxx>
45#include <sfx2/event.hxx>
46#include <swerror.h>
47
48constexpr OUStringLiteral XMLN_BLOCKLIST = u"BlockList.xml";
49
50using namespace ::com::sun::star;
51using namespace ::com::sun::star::uno;
52using namespace ::com::sun::star::container;
53using namespace css::xml::sax;
54using namespace xmloff::token;
55
56using ::xmloff::token::XML_BLOCK_LIST;
57using ::xmloff::token::XML_UNFORMATTED_TEXT;
58using ::xmloff::token::GetXMLToken;
59
61{
62 OUString aFolderName ( GetPackageName ( nIdx ) );
63
64 if (!IsOnlyTextBlock ( nIdx ) )
65 {
66 try
67 {
68 m_xRoot = m_xBlkRoot->openStorageElement( aFolderName, embed::ElementModes::READ );
69 m_xMedium = new SfxMedium( m_xRoot, GetBaseURL(), "writer8" );
70 SwReader aReader( *m_xMedium, aFolderName, m_xDoc.get() );
71 ReadXML->SetBlockMode( true );
72 aReader.Read( *ReadXML );
73 ReadXML->SetBlockMode( false );
74 // Ole objects fail to display when inserted into the document, as
75 // the ObjectReplacement folder and contents are missing
76 OUString sObjReplacements( "ObjectReplacements" );
77 if ( m_xRoot->hasByName( sObjReplacements ) )
78 {
79 uno::Reference< document::XStorageBasedDocument > xDocStor( m_xDoc->GetDocShell()->GetModel(), uno::UNO_QUERY_THROW );
80 uno::Reference< embed::XStorage > xStr( xDocStor->getDocumentStorage() );
81 if ( xStr.is() )
82 {
83 m_xRoot->copyElementTo( sObjReplacements, xStr, sObjReplacements );
84 uno::Reference< embed::XTransactedObject > xTrans( xStr, uno::UNO_QUERY );
85 if ( xTrans.is() )
86 xTrans->commit();
87 }
88 }
89 }
90 catch( uno::Exception& )
91 {
92 }
93
94 m_xRoot = nullptr;
95 }
96 else
97 {
98 OUString aStreamName = aFolderName + ".xml";
99 try
100 {
101 m_xRoot = m_xBlkRoot->openStorageElement( aFolderName, embed::ElementModes::READ );
102 uno::Reference < io::XStream > xStream = m_xRoot->openStreamElement( aStreamName, embed::ElementModes::READ );
103
104 uno::Reference< uno::XComponentContext > xContext =
106
107 xml::sax::InputSource aParserInput;
108 aParserInput.sSystemId = m_aNames[nIdx]->m_aPackageName;
109
110 aParserInput.aInputStream = xStream->getInputStream();
111
112 // get filter
113 uno::Reference< xml::sax::XFastDocumentHandler > xFilter = new SwXMLTextBlockImport( xContext, m_aCurrentText, true );
114 uno::Reference< xml::sax::XFastTokenHandler > xTokenHandler = new SwXMLTextBlockTokenHandler();
115
116 // connect parser and filter
117 uno::Reference< xml::sax::XFastParser > xParser = xml::sax::FastParser::create(xContext);
118 xParser->setFastDocumentHandler( xFilter );
119 xParser->setTokenHandler( xTokenHandler );
120
121 xParser->registerNamespace( "http://openoffice.org/2000/text", FastToken::NAMESPACE | XML_NAMESPACE_TEXT );
122 xParser->registerNamespace( "http://openoffice.org/2000/office", FastToken::NAMESPACE | XML_NAMESPACE_OFFICE );
123
124 // parse
125 try
126 {
127 xParser->parseStream( aParserInput );
128 }
129 catch( xml::sax::SAXParseException& )
130 {
131 // re throw ?
132 }
133 catch( xml::sax::SAXException& )
134 {
135 // re throw ?
136 }
137 catch( io::IOException& )
138 {
139 // re throw ?
140 }
141
142 m_bInfoChanged = false;
144 }
145 catch( uno::Exception& )
146 {
147 }
148
149 m_xRoot = nullptr;
150 }
151 return ERRCODE_NONE;
152}
153
154// event description for autotext events; this constant should really be
155// taken from unocore/unoevents.cxx or ui/unotxt.cxx
157{
158 { SvMacroItemId::SwStartInsGlossary, "OnInsertStart" },
159 { SvMacroItemId::SwEndInsGlossary, "OnInsertDone" },
160 { SvMacroItemId::NONE, nullptr }
161};
162
164 SvxMacroTableDtor& rMacroTable )
165{
166 // set current auto text
167 m_aShort = m_aNames[nIdx]->m_aShort;
168 m_aLong = m_aNames[nIdx]->m_aLong;
169 m_aPackageName = m_aNames[nIdx]->m_aPackageName;
170
171 // open stream in proper sub-storage
172 CloseFile();
173 if ( OpenFile() != ERRCODE_NONE )
174 return ERR_SWG_READ_ERROR;
175
176 try
177 {
178 m_xRoot = m_xBlkRoot->openStorageElement( m_aPackageName, embed::ElementModes::READ );
180
181 uno::Reference < io::XStream > xDocStream = m_xRoot->openStreamElement(
182 "atevent.xml", embed::ElementModes::READ );
183 OSL_ENSURE(xDocStream.is(), "Can't create stream");
184 if ( !xDocStream.is() )
185 return ERR_SWG_READ_ERROR;
186
187 uno::Reference<io::XInputStream> xInputStream = xDocStream->getInputStream();
188
189 // prepare ParserInputSource
190 xml::sax::InputSource aParserInput;
191 aParserInput.sSystemId = m_aName;
192 aParserInput.aInputStream = xInputStream;
193
194 // get service factory
195 uno::Reference< uno::XComponentContext > xContext =
197
198 // get parser
199 uno::Reference< xml::sax::XParser > xParser = xml::sax::Parser::create( xContext );
200
201 // create descriptor and reference to it. Either
202 // both or neither must be kept because of the
203 // reference counting!
206 Sequence<Any> aFilterArguments{ Any(uno::Reference<XNameReplace>(pDescriptor)) };
207
208 // get filter
209 OUString sFilterComponent = bOasis
210 ? OUString("com.sun.star.comp.Writer.XMLOasisAutotextEventsImporter")
211 : OUString("com.sun.star.comp.Writer.XMLAutotextEventsImporter");
212 uno::Reference< xml::sax::XDocumentHandler > xFilter(
213 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
214 sFilterComponent, aFilterArguments, xContext),
215 UNO_QUERY );
216 OSL_ENSURE( xFilter.is(), "can't instantiate autotext-events filter");
217 if ( !xFilter.is() )
218 return ERR_SWG_READ_ERROR;
219
220 // connect parser and filter
221 xParser->setDocumentHandler( xFilter );
222
223 // parse the stream
224 try
225 {
226 xParser->parseStream( aParserInput );
227 }
228 catch( xml::sax::SAXParseException& )
229 {
230 // workaround for #83452#: SetSize doesn't work
231 // nRet = ERR_SWG_READ_ERROR;
232 }
233 catch( xml::sax::SAXException& )
234 {
235 TOOLS_WARN_EXCEPTION("sw", "");
236 return ERR_SWG_READ_ERROR;
237 }
238 catch( io::IOException& )
239 {
240 TOOLS_WARN_EXCEPTION("sw", "");
241 return ERR_SWG_READ_ERROR;
242 }
243
244 // and finally, copy macro into table
245 pDescriptor->copyMacrosIntoTable(rMacroTable);
246 }
247 catch( uno::Exception& )
248 {
249 TOOLS_WARN_EXCEPTION("sw", "");
250 return ERR_SWG_READ_ERROR;
251 }
252
253 // success!
254 return ERRCODE_NONE;
255}
256
257ErrCode SwXMLTextBlocks::GetBlockText( std::u16string_view rShort, OUString& rText )
258{
259 OUString aFolderName = GeneratePackageName ( rShort );
260 OUString aStreamName = aFolderName + ".xml";
261 rText.clear();
262
263 try
264 {
265 bool bTextOnly = true;
266
267 m_xRoot = m_xBlkRoot->openStorageElement( aFolderName, embed::ElementModes::READ );
268 if ( !m_xRoot->hasByName( aStreamName ) || !m_xRoot->isStreamElement( aStreamName ) )
269 {
270 bTextOnly = false;
271 aStreamName = "content.xml";
272 }
273
274 uno::Reference < io::XStream > xContents = m_xRoot->openStreamElement( aStreamName, embed::ElementModes::READ );
275 uno::Reference< uno::XComponentContext > xContext =
277
278 xml::sax::InputSource aParserInput;
279 aParserInput.sSystemId = m_aName;
280 aParserInput.aInputStream = xContents->getInputStream();
281
282 // get filter
283 uno::Reference< xml::sax::XFastDocumentHandler > xFilter = new SwXMLTextBlockImport( xContext, rText, bTextOnly );
284 uno::Reference< xml::sax::XFastTokenHandler > xTokenHandler = new SwXMLTextBlockTokenHandler();
285
286 // connect parser and filter
287 uno::Reference< xml::sax::XFastParser > xParser = xml::sax::FastParser::create(xContext);
288 xParser->setFastDocumentHandler( xFilter );
289 xParser->setTokenHandler( xTokenHandler );
290
291 xParser->registerNamespace( "urn:oasis:names:tc:opendocument:xmlns:office:1.0", FastToken::NAMESPACE | XML_NAMESPACE_OFFICE );
292 xParser->registerNamespace( "urn:oasis:names:tc:opendocument:xmlns:text:1.0", FastToken::NAMESPACE | XML_NAMESPACE_TEXT );
293
294 // parse
295 try
296 {
297 xParser->parseStream( aParserInput );
298 }
299 catch( xml::sax::SAXParseException& )
300 {
301 // re throw ?
302 }
303 catch( xml::sax::SAXException& )
304 {
305 // re throw ?
306 }
307 catch( io::IOException& )
308 {
309 // re throw ?
310 }
311
312 m_xRoot = nullptr;
313 }
314 catch ( uno::Exception& )
315 {
316 OSL_FAIL( "Tried to open non-existent folder or stream!");
317 }
318
319 return ERRCODE_NONE;
320}
321
323 std::u16string_view rText, const OUString& rPackageName )
324{
325 GetIndex ( rShort );
326 /*
327 if (xBlkRoot->IsContained ( rPackageName ) )
328 {
329 xBlkRoot->Remove ( rPackageName );
330 xBlkRoot->Commit ( );
331 }
332 */
333 OUString aStreamName = rPackageName + ".xml";
334
335 uno::Reference< uno::XComponentContext > xContext =
337
338 uno::Reference < xml::sax::XWriter > xWriter = xml::sax::Writer::create(xContext);
339 ErrCode nRes = ERRCODE_NONE;
340
341 try
342 {
343 m_xRoot = m_xBlkRoot->openStorageElement( rPackageName, embed::ElementModes::WRITE );
344 uno::Reference < io::XStream > xDocStream = m_xRoot->openStreamElement( aStreamName,
345 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
346
347 uno::Reference < beans::XPropertySet > xSet( xDocStream, uno::UNO_QUERY );
348 xSet->setPropertyValue("MediaType", Any(OUString( "text/xml" )) );
349 uno::Reference < io::XOutputStream > xOut = xDocStream->getOutputStream();
350 xWriter->setOutputStream(xOut);
351
353
354 xExp->exportDoc( rText );
355
356 uno::Reference < embed::XTransactedObject > xTrans( m_xRoot, uno::UNO_QUERY );
357 if ( xTrans.is() )
358 xTrans->commit();
359
361 {
362 uno::Reference < embed::XTransactedObject > xTmpTrans( m_xBlkRoot, uno::UNO_QUERY );
363 if ( xTmpTrans.is() )
364 xTmpTrans->commit();
365 }
366 }
367 catch ( uno::Exception& )
368 {
369 nRes = ERR_SWG_WRITE_ERROR;
370 }
371
372 m_xRoot = nullptr;
373
374 //TODO/LATER: error handling
375 /*
376 sal_uLong nErr = xBlkRoot->GetError();
377 sal_uLong nRes = 0;
378 if( nErr == SVSTREAM_DISK_FULL )
379 nRes = ERR_W4W_WRITE_FULL;
380 else if( nErr != ERRCODE_NONE )
381 nRes = ERR_SWG_WRITE_ERROR;
382 */
383 if( !nRes ) // So that we can access the Doc via GetText & nCur
384 MakeBlockText( rText );
385
386 return nRes;
387}
388
390{
391 const OUString sDocName( XMLN_BLOCKLIST );
392 try
393 {
394 if ( !m_xBlkRoot.is() || !m_xBlkRoot->hasByName( sDocName ) || !m_xBlkRoot->isStreamElement( sDocName ) )
395 return;
396
397 uno::Reference< uno::XComponentContext > xContext =
399
400 xml::sax::InputSource aParserInput;
401 aParserInput.sSystemId = sDocName;
402
403 uno::Reference < io::XStream > xDocStream = m_xBlkRoot->openStreamElement( sDocName, embed::ElementModes::READ );
404 aParserInput.aInputStream = xDocStream->getInputStream();
405
406 // get filter
407 uno::Reference< xml::sax::XFastDocumentHandler > xFilter = new SwXMLBlockListImport( xContext, *this );
408 uno::Reference< xml::sax::XFastTokenHandler > xTokenHandler = new SwXMLBlockListTokenHandler();
409
410 // connect parser and filter
411 uno::Reference< xml::sax::XFastParser > xParser = xml::sax::FastParser::create(xContext);
412 xParser->setFastDocumentHandler( xFilter );
413 xParser->registerNamespace( "http://openoffice.org/2001/block-list", FastToken::NAMESPACE | XML_NAMESPACE_BLOCKLIST );
414 xParser->setTokenHandler( xTokenHandler );
415
416 // parse
417 xParser->parseStream( aParserInput );
418 }
419 catch ( uno::Exception& )
420 {
421 TOOLS_WARN_EXCEPTION("sw", "when loading " << sDocName);
422 // re throw ?
423 }
424}
426{
427 if ( !(m_xBlkRoot.is() || ERRCODE_NONE == OpenFile ( false )) )
428 return;
429
430 uno::Reference< uno::XComponentContext > xContext =
432
433 uno::Reference < xml::sax::XWriter > xWriter = xml::sax::Writer::create(xContext);
434
435 /*
436 if ( xBlkRoot->IsContained( sDocName) )
437 {
438 xBlkRoot->Remove ( sDocName );
439 xBlkRoot->Commit();
440 }
441 */
442
443 try
444 {
445 uno::Reference < io::XStream > xDocStream = m_xBlkRoot->openStreamElement( XMLN_BLOCKLIST,
446 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
447
448 uno::Reference < beans::XPropertySet > xSet( xDocStream, uno::UNO_QUERY );
449 xSet->setPropertyValue("MediaType", Any(OUString( "text/xml" )) );
450 uno::Reference < io::XOutputStream > xOut = xDocStream->getOutputStream();
451 xWriter->setOutputStream(xOut);
452
453 rtl::Reference<SwXMLBlockListExport> xExp(new SwXMLBlockListExport( xContext, *this, XMLN_BLOCKLIST, xWriter) );
454
455 xExp->exportDoc( XML_BLOCK_LIST );
456
457 uno::Reference < embed::XTransactedObject > xTrans( m_xBlkRoot, uno::UNO_QUERY );
458 if ( xTrans.is() )
459 xTrans->commit();
460 }
461 catch ( uno::Exception& )
462 {
463 }
464
465 m_bInfoChanged = false;
466 return;
467}
468
470 sal_uInt16 nIdx,
471 const SvxMacroTableDtor& rMacroTable )
472{
473 // set current autotext
474 m_aShort = m_aNames[nIdx]->m_aShort;
475 m_aLong = m_aNames[nIdx]->m_aLong;
476 m_aPackageName = m_aNames[nIdx]->m_aPackageName;
477
478 // start XML autotext event export
479 ErrCode nRes = ERRCODE_NONE;
480
481 uno::Reference< uno::XComponentContext > xContext =
483
484 // Get model
485 uno::Reference< lang::XComponent > xModelComp =
486 m_xDoc->GetDocShell()->GetModel();
487 OSL_ENSURE( xModelComp.is(), "XMLWriter::Write: got no model" );
488 if( !xModelComp.is() )
489 return ERR_SWG_WRITE_ERROR;
490
491 // open stream in proper sub-storage
492 CloseFile(); // close (it may be open in read-only-mode)
493 nRes = OpenFile ( false );
494
495 if ( ERRCODE_NONE == nRes )
496 {
497 try
498 {
499 m_xRoot = m_xBlkRoot->openStorageElement( m_aPackageName, embed::ElementModes::WRITE );
501
502 uno::Reference < io::XStream > xDocStream = m_xRoot->openStreamElement( "atevent.xml",
503 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
504
505 uno::Reference < beans::XPropertySet > xSet( xDocStream, uno::UNO_QUERY );
506 xSet->setPropertyValue("MediaType", Any(OUString( "text/xml" )) );
507 uno::Reference < io::XOutputStream > xOutputStream = xDocStream->getOutputStream();
508
509 // get XML writer
510 uno::Reference< xml::sax::XWriter > xSaxWriter =
511 xml::sax::Writer::create( xContext );
512
513 // connect XML writer to output stream
514 xSaxWriter->setOutputStream( xOutputStream );
515
516 // construct events object
517 uno::Reference<XNameAccess> xEvents =
519
520 // prepare arguments (prepend doc handler to given arguments)
521 Sequence<Any> aParams{ Any(xSaxWriter), Any(xEvents) };
522
523 // get filter component
524 OUString sFilterComponent = bOasis
525 ? OUString("com.sun.star.comp.Writer.XMLOasisAutotextEventsExporter")
526 : OUString("com.sun.star.comp.Writer.XMLAutotextEventsExporter");
527 uno::Reference< document::XExporter > xExporter(
528 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
529 sFilterComponent, aParams, xContext), UNO_QUERY);
530 OSL_ENSURE( xExporter.is(),
531 "can't instantiate export filter component" );
532 if( xExporter.is() )
533 {
534 // connect model and filter
535 xExporter->setSourceDocument( xModelComp );
536
537 // filter!
538 Sequence<beans::PropertyValue> aFilterProps( 0 );
539 uno::Reference < document::XFilter > xFilter( xExporter,
540 UNO_QUERY );
541 xFilter->filter( aFilterProps );
542 }
543 else
544 nRes = ERR_SWG_WRITE_ERROR;
545
546 // finally, commit stream, sub-storage and storage
547 uno::Reference < embed::XTransactedObject > xTmpTrans( m_xRoot, uno::UNO_QUERY );
548 if ( xTmpTrans.is() )
549 xTmpTrans->commit();
550
551 uno::Reference < embed::XTransactedObject > xTrans( m_xBlkRoot, uno::UNO_QUERY );
552 if ( xTrans.is() )
553 xTrans->commit();
554
555 m_xRoot = nullptr;
556 }
557 catch ( uno::Exception& )
558 {
559 nRes = ERR_SWG_WRITE_ERROR;
560 }
561
562 CloseFile();
563 }
564 else
565 nRes = ERR_SWG_WRITE_ERROR;
566
567 return nRes;
568}
569
570/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const struct SvEventDescription aAutotextEvents[]
constexpr OUStringLiteral XMLN_BLOCKLIST
Reference< XInputStream > xStream
void SetBlockMode(bool bSet)
Definition: shellio.hxx:255
sal_Int32 GetVersion() const
OUString m_aName
Definition: swblocks.hxx:59
OUString m_aShort
Definition: swblocks.hxx:61
const OUString & GetBaseURL() const
Definition: swblocks.hxx:104
OUString GetPackageName(sal_uInt16) const
Return longname for index.
Definition: swblocks.cxx:169
OUString m_aLong
Definition: swblocks.hxx:61
sal_uInt16 GetIndex(const OUString &) const
Get count of Text Blocks.
Definition: swblocks.cxx:128
SwBlockNames m_aNames
Definition: swblocks.hxx:63
rtl::Reference< SwDoc > m_xDoc
Definition: swblocks.hxx:66
OUString m_aCurrentText
Definition: swblocks.hxx:60
bool m_bInfoChanged
Definition: swblocks.hxx:70
ErrCode Read(const Reader &)
Definition: shellio.cxx:91
SwDoc * GetDoc() const
virtual bool IsOnlyTextBlock(const OUString &rShort) const override
css::uno::Reference< css::embed::XStorage > m_xBlkRoot
void MakeBlockText(std::u16string_view rText)
static OUString GeneratePackageName(std::u16string_view rShort)
ErrCode GetBlockText(std::u16string_view rShort, OUString &rText)
tools::SvRef< SfxMedium > m_xMedium
virtual ErrCode GetMacroTable(sal_uInt16, SvxMacroTableDtor &rMacroTable) override
virtual ErrCode SetMacroTable(sal_uInt16 nIdx, const SvxMacroTableDtor &rMacroTable) override
ErrCode PutBlockText(const OUString &rShort, std::u16string_view rText, const OUString &rPackageName)
virtual void CloseFile() override
css::uno::Reference< css::embed::XStorage > m_xRoot
virtual ErrCode OpenFile(bool bReadOnly=true) override
#define TOOLS_WARN_EXCEPTION(area, stream)
float u
#define ERRCODE_NONE
#define SOFFICE_FILEFORMAT_60
Reader * ReadXML
Definition: fltini.cxx:46
Reference< XComponentContext > getProcessComponentContext()
XML_BLOCK_LIST
XML_UNFORMATTED_TEXT
const OUString & GetXMLToken(enum XMLTokenEnum eToken)
#define ERR_SWG_WRITE_ERROR
Definition: swerror.h:30
#define ERR_SWG_READ_ERROR
Definition: swerror.h:25
constexpr sal_uInt16 XML_NAMESPACE_BLOCKLIST
constexpr sal_uInt16 XML_NAMESPACE_TEXT
constexpr sal_uInt16 XML_NAMESPACE_OFFICE