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/Parser.hpp>
33 #include <com/sun/star/xml/sax/FastParser.hpp>
34 #include <com/sun/star/xml/sax/FastToken.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/xmlnmspe.hxx>
45 #include <sfx2/event.hxx>
46 #include <swerror.h>
47 
48 const char XMLN_BLOCKLIST[] = "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  xRoot = xBlkRoot->openStorageElement( aFolderName, embed::ElementModes::READ );
69  xMedium = new SfxMedium( xRoot, GetBaseURL(), "writer8" );
70  SwReader aReader( *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 ( 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  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  xRoot = nullptr;
95  }
96  else
97  {
98  OUString aStreamName = aFolderName + ".xml";
99  try
100  {
101  xRoot = xBlkRoot->openStorageElement( aFolderName, embed::ElementModes::READ );
102  uno::Reference < io::XStream > xStream = 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]->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  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]->aShort;
168  m_aLong = m_aNames[nIdx]->aLong;
169  aPackageName = m_aNames[nIdx]->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  xRoot = xBlkRoot->openStorageElement( aPackageName, embed::ElementModes::READ );
179  bool bOasis = SotStorage::GetVersion( xRoot ) > SOFFICE_FILEFORMAT_60;
180 
181  uno::Reference < io::XStream > xDocStream = 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 ParserInputSrouce
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  // create descriptor and reference to it. Either
199  // both or neither must be kept because of the
200  // reference counting!
201  SvMacroTableEventDescriptor* pDescriptor =
202  new SvMacroTableEventDescriptor(aAutotextEvents);
203  uno::Reference<XNameReplace> xReplace = pDescriptor;
204  Sequence<Any> aFilterArguments( 1 );
205  aFilterArguments[0] <<= xReplace;
206 
207  // get filter
208  OUString sFilterComponent = bOasis
209  ? OUString("com.sun.star.comp.Writer.XMLOasisAutotextEventsImporter")
210  : OUString("com.sun.star.comp.Writer.XMLAutotextEventsImporter");
211  uno::Reference< xml::sax::XFastParser > xFilter(
212  xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
213  sFilterComponent, aFilterArguments, xContext),
214  UNO_QUERY_THROW );
215 
216  // parse the stream
217  try
218  {
219  xFilter->parseStream( aParserInput );
220  }
221  catch( xml::sax::SAXParseException& )
222  {
223  // workaround for #83452#: SetSize doesn't work
224  // nRet = ERR_SWG_READ_ERROR;
225  }
226  catch( xml::sax::SAXException& )
227  {
228  TOOLS_WARN_EXCEPTION("sw", "");
229  return ERR_SWG_READ_ERROR;
230  }
231  catch( io::IOException& )
232  {
233  TOOLS_WARN_EXCEPTION("sw", "");
234  return ERR_SWG_READ_ERROR;
235  }
236 
237  // and finally, copy macro into table
238  pDescriptor->copyMacrosIntoTable(rMacroTable);
239  }
240  catch( uno::Exception& )
241  {
242  TOOLS_WARN_EXCEPTION("sw", "");
243  return ERR_SWG_READ_ERROR;
244  }
245 
246  // success!
247  return ERRCODE_NONE;
248 }
249 
250 ErrCode SwXMLTextBlocks::GetBlockText( const OUString& rShort, OUString& rText )
251 {
252  OUString aFolderName = GeneratePackageName ( rShort );
253  OUString aStreamName = aFolderName + ".xml";
254  rText.clear();
255 
256  try
257  {
258  bool bTextOnly = true;
259 
260  xRoot = xBlkRoot->openStorageElement( aFolderName, embed::ElementModes::READ );
261  if ( !xRoot->hasByName( aStreamName ) || !xRoot->isStreamElement( aStreamName ) )
262  {
263  bTextOnly = false;
264  aStreamName = "content.xml";
265  }
266 
267  uno::Reference < io::XStream > xContents = xRoot->openStreamElement( aStreamName, embed::ElementModes::READ );
268  uno::Reference< uno::XComponentContext > xContext =
270 
271  xml::sax::InputSource aParserInput;
272  aParserInput.sSystemId = m_aName;
273  aParserInput.aInputStream = xContents->getInputStream();
274 
275  // get filter
276  uno::Reference< xml::sax::XFastDocumentHandler > xFilter = new SwXMLTextBlockImport( xContext, rText, bTextOnly );
277  uno::Reference< xml::sax::XFastTokenHandler > xTokenHandler = new SwXMLTextBlockTokenHandler();
278 
279  // connect parser and filter
280  uno::Reference< xml::sax::XFastParser > xParser = xml::sax::FastParser::create(xContext);
281  xParser->setFastDocumentHandler( xFilter );
282  xParser->setTokenHandler( xTokenHandler );
283 
284  xParser->registerNamespace( "urn:oasis:names:tc:opendocument:xmlns:office:1.0", FastToken::NAMESPACE | XML_NAMESPACE_OFFICE );
285  xParser->registerNamespace( "urn:oasis:names:tc:opendocument:xmlns:text:1.0", FastToken::NAMESPACE | XML_NAMESPACE_TEXT );
286 
287  // parse
288  try
289  {
290  xParser->parseStream( aParserInput );
291  }
292  catch( xml::sax::SAXParseException& )
293  {
294  // re throw ?
295  }
296  catch( xml::sax::SAXException& )
297  {
298  // re throw ?
299  }
300  catch( io::IOException& )
301  {
302  // re throw ?
303  }
304 
305  xRoot = nullptr;
306  }
307  catch ( uno::Exception& )
308  {
309  OSL_FAIL( "Tried to open non-existent folder or stream!");
310  }
311 
312  return ERRCODE_NONE;
313 }
314 
315 ErrCode SwXMLTextBlocks::PutBlockText( const OUString& rShort,
316  const OUString& rText, const OUString& rPackageName )
317 {
318  GetIndex ( rShort );
319  /*
320  if (xBlkRoot->IsContained ( rPackageName ) )
321  {
322  xBlkRoot->Remove ( rPackageName );
323  xBlkRoot->Commit ( );
324  }
325  */
326  OUString aStreamName = rPackageName + ".xml";
327 
328  uno::Reference< uno::XComponentContext > xContext =
330 
331  uno::Reference < xml::sax::XWriter > xWriter = xml::sax::Writer::create(xContext);
332  ErrCode nRes = ERRCODE_NONE;
333 
334  try
335  {
336  xRoot = xBlkRoot->openStorageElement( rPackageName, embed::ElementModes::WRITE );
337  uno::Reference < io::XStream > xDocStream = xRoot->openStreamElement( aStreamName,
338  embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
339 
340  uno::Reference < beans::XPropertySet > xSet( xDocStream, uno::UNO_QUERY );
341  xSet->setPropertyValue("MediaType", Any(OUString( "text/xml" )) );
342  uno::Reference < io::XOutputStream > xOut = xDocStream->getOutputStream();
343  xWriter->setOutputStream(xOut);
344 
346 
347  xExp->exportDoc( rText );
348 
349  uno::Reference < embed::XTransactedObject > xTrans( xRoot, uno::UNO_QUERY );
350  if ( xTrans.is() )
351  xTrans->commit();
352 
353  if (! (nFlags & SwXmlFlags::NoRootCommit) )
354  {
355  uno::Reference < embed::XTransactedObject > xTmpTrans( xBlkRoot, uno::UNO_QUERY );
356  if ( xTmpTrans.is() )
357  xTmpTrans->commit();
358  }
359  }
360  catch ( uno::Exception& )
361  {
362  nRes = ERR_SWG_WRITE_ERROR;
363  }
364 
365  xRoot = nullptr;
366 
367  //TODO/LATER: error handling
368  /*
369  sal_uLong nErr = xBlkRoot->GetError();
370  sal_uLong nRes = 0;
371  if( nErr == SVSTREAM_DISK_FULL )
372  nRes = ERR_W4W_WRITE_FULL;
373  else if( nErr != ERRCODE_NONE )
374  nRes = ERR_SWG_WRITE_ERROR;
375  */
376  if( !nRes ) // So that we can access the Doc via GetText & nCur
377  MakeBlockText( rText );
378 
379  return nRes;
380 }
381 
383 {
384  const OUString sDocName( XMLN_BLOCKLIST );
385  try
386  {
387  if ( !xBlkRoot.is() || !xBlkRoot->hasByName( sDocName ) || !xBlkRoot->isStreamElement( sDocName ) )
388  return;
389 
390  uno::Reference< uno::XComponentContext > xContext =
392 
393  xml::sax::InputSource aParserInput;
394  aParserInput.sSystemId = sDocName;
395 
396  uno::Reference < io::XStream > xDocStream = xBlkRoot->openStreamElement( sDocName, embed::ElementModes::READ );
397  aParserInput.aInputStream = xDocStream->getInputStream();
398 
399  // get filter
400  uno::Reference< xml::sax::XFastDocumentHandler > xFilter = new SwXMLBlockListImport( xContext, *this );
401  uno::Reference< xml::sax::XFastTokenHandler > xTokenHandler = new SwXMLBlockListTokenHandler();
402 
403  // connect parser and filter
404  uno::Reference< xml::sax::XFastParser > xParser = xml::sax::FastParser::create(xContext);
405  xParser->setFastDocumentHandler( xFilter );
406  xParser->registerNamespace( "http://openoffice.org/2001/block-list", FastToken::NAMESPACE | XML_NAMESPACE_BLOCKLIST );
407  xParser->setTokenHandler( xTokenHandler );
408 
409  // parse
410  xParser->parseStream( aParserInput );
411  }
412  catch ( uno::Exception& )
413  {
414  TOOLS_WARN_EXCEPTION("sw", "when loading " << sDocName);
415  // re throw ?
416  }
417 }
419 {
420  if ( xBlkRoot.is() || ERRCODE_NONE == OpenFile ( false ) )
421  {
422  uno::Reference< uno::XComponentContext > xContext =
424 
425  uno::Reference < xml::sax::XWriter > xWriter = xml::sax::Writer::create(xContext);
426 
427  /*
428  if ( xBlkRoot->IsContained( sDocName) )
429  {
430  xBlkRoot->Remove ( sDocName );
431  xBlkRoot->Commit();
432  }
433  */
434 
435  try
436  {
437  uno::Reference < io::XStream > xDocStream = xBlkRoot->openStreamElement( XMLN_BLOCKLIST,
438  embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
439 
440  uno::Reference < beans::XPropertySet > xSet( xDocStream, uno::UNO_QUERY );
441  xSet->setPropertyValue("MediaType", Any(OUString( "text/xml" )) );
442  uno::Reference < io::XOutputStream > xOut = xDocStream->getOutputStream();
443  xWriter->setOutputStream(xOut);
444 
445  rtl::Reference<SwXMLBlockListExport> xExp(new SwXMLBlockListExport( xContext, *this, XMLN_BLOCKLIST, xWriter) );
446 
447  xExp->exportDoc( XML_BLOCK_LIST );
448 
449  uno::Reference < embed::XTransactedObject > xTrans( xBlkRoot, uno::UNO_QUERY );
450  if ( xTrans.is() )
451  xTrans->commit();
452  }
453  catch ( uno::Exception& )
454  {
455  }
456 
457  m_bInfoChanged = false;
458  return;
459  }
460 }
461 
463  sal_uInt16 nIdx,
464  const SvxMacroTableDtor& rMacroTable )
465 {
466  // set current autotext
467  m_aShort = m_aNames[nIdx]->aShort;
468  m_aLong = m_aNames[nIdx]->aLong;
469  aPackageName = m_aNames[nIdx]->aPackageName;
470 
471  // start XML autotext event export
472  ErrCode nRes = ERRCODE_NONE;
473 
474  uno::Reference< uno::XComponentContext > xContext =
476 
477  // Get model
478  uno::Reference< lang::XComponent > xModelComp =
479  m_xDoc->GetDocShell()->GetModel();
480  OSL_ENSURE( xModelComp.is(), "XMLWriter::Write: got no model" );
481  if( !xModelComp.is() )
482  return ERR_SWG_WRITE_ERROR;
483 
484  // open stream in proper sub-storage
485  CloseFile(); // close (it may be open in read-only-mode)
486  nRes = OpenFile ( false );
487 
488  if ( ERRCODE_NONE == nRes )
489  {
490  try
491  {
492  xRoot = xBlkRoot->openStorageElement( aPackageName, embed::ElementModes::WRITE );
493  bool bOasis = SotStorage::GetVersion( xRoot ) > SOFFICE_FILEFORMAT_60;
494 
495  uno::Reference < io::XStream > xDocStream = xRoot->openStreamElement( "atevent.xml",
496  embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
497 
498  uno::Reference < beans::XPropertySet > xSet( xDocStream, uno::UNO_QUERY );
499  xSet->setPropertyValue("MediaType", Any(OUString( "text/xml" )) );
500  uno::Reference < io::XOutputStream > xOutputStream = xDocStream->getOutputStream();
501 
502  // get XML writer
503  uno::Reference< xml::sax::XWriter > xSaxWriter =
504  xml::sax::Writer::create( xContext );
505 
506  // connect XML writer to output stream
507  xSaxWriter->setOutputStream( xOutputStream );
508 
509  // construct events object
510  uno::Reference<XNameAccess> xEvents =
511  new SvMacroTableEventDescriptor(rMacroTable,aAutotextEvents);
512 
513  // prepare arguments (prepend doc handler to given arguments)
514  Sequence<Any> aParams(2);
515  aParams[0] <<= xSaxWriter;
516  aParams[1] <<= xEvents;
517 
518  // get filter component
519  OUString sFilterComponent = bOasis
520  ? OUString("com.sun.star.comp.Writer.XMLOasisAutotextEventsExporter")
521  : OUString("com.sun.star.comp.Writer.XMLAutotextEventsExporter");
522  uno::Reference< document::XExporter > xExporter(
523  xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
524  sFilterComponent, aParams, xContext), UNO_QUERY);
525  OSL_ENSURE( xExporter.is(),
526  "can't instantiate export filter component" );
527  if( xExporter.is() )
528  {
529  // connect model and filter
530  xExporter->setSourceDocument( xModelComp );
531 
532  // filter!
533  Sequence<beans::PropertyValue> aFilterProps( 0 );
534  uno::Reference < document::XFilter > xFilter( xExporter,
535  UNO_QUERY );
536  xFilter->filter( aFilterProps );
537  }
538  else
539  nRes = ERR_SWG_WRITE_ERROR;
540 
541  // finally, commit stream, sub-storage and storage
542  uno::Reference < embed::XTransactedObject > xTmpTrans( xRoot, uno::UNO_QUERY );
543  if ( xTmpTrans.is() )
544  xTmpTrans->commit();
545 
546  uno::Reference < embed::XTransactedObject > xTrans( xBlkRoot, uno::UNO_QUERY );
547  if ( xTrans.is() )
548  xTrans->commit();
549 
550  xRoot = nullptr;
551  }
552  catch ( uno::Exception& )
553  {
554  nRes = ERR_SWG_WRITE_ERROR;
555  }
556 
557  CloseFile();
558  }
559  else
560  nRes = ERR_SWG_WRITE_ERROR;
561 
562  return nRes;
563 }
564 
565 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const struct SvEventDescription aAutotextEvents[]
#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)
XML_UNFORMATTED_TEXT
constexpr sal_uInt16 XML_NAMESPACE_TEXT
const char XMLN_BLOCKLIST[]
Reader * ReadXML
Definition: fltini.cxx:48
Reference< XInputStream > xStream
constexpr sal_uInt16 XML_NAMESPACE_BLOCKLIST
void SetBlockMode(bool bSet)
Definition: shellio.hxx:263
OUString m_aName
#define SOFFICE_FILEFORMAT_60
#define TOOLS_WARN_EXCEPTION(area, stream)
SwDoc * GetDoc() const
virtual ErrCode GetMacroTable(sal_uInt16, SvxMacroTableDtor &rMacroTable) override
XML_BLOCK_LIST
#define ERRCODE_NONE
const OUString & GetXMLToken(enum XMLTokenEnum eToken)
Reference< XComponentContext > getProcessComponentContext()
ErrCode GetBlockText(const OUString &rShort, OUString &rText)
#define ERR_SWG_READ_ERROR
Definition: swerror.h:25
void copyMacrosIntoTable(SvxMacroTableDtor &aFmt)
constexpr sal_uInt16 XML_NAMESPACE_OFFICE