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/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>
44 #include <xmloff/xmlnamespace.hxx>
45 #include <sfx2/event.hxx>
46 #include <swerror.h>
47 
48 constexpr OUStringLiteral XMLN_BLOCKLIST = u"BlockList.xml";
49 
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::uno;
52 using namespace ::com::sun::star::container;
53 using namespace css::xml::sax;
54 using namespace xmloff::token;
55 
56 using ::xmloff::token::XML_BLOCK_LIST;
57 using ::xmloff::token::XML_UNFORMATTED_TEXT;
58 using ::xmloff::token::GetXMLToken;
59 
60 ErrCode SwXMLTextBlocks::GetDoc( sal_uInt16 nIdx )
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;
143  MakeBlockText(m_aCurrentText);
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!
205  new SvMacroTableEventDescriptor(aAutotextEvents);
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 
257 ErrCode 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 
322 ErrCode SwXMLTextBlocks::PutBlockText( const OUString& rShort,
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 =
518  new SvMacroTableEventDescriptor(rMacroTable,aAutotextEvents);
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 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
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
ErrCode PutBlockText(const OUString &rShort, std::u16string_view rText, const OUString &rPackageName)
#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