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