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