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