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 <TokenWriter.hxx>
21 #include <tools/diagnose_ex.h>
22 #include <tools/stream.hxx>
23 #include <osl/diagnose.h>
24 #include <rtl/tencinfo.h>
25 #include <sal/log.hxx>
26 #include <i18nlangtag/languagetag.hxx>
27 #include <RtfReader.hxx>
28 #include <HtmlReader.hxx>
29 #include <strings.hxx>
30 #include <comphelper/types.hxx>
31 #include <connectivity/dbtools.hxx>
32 #include <com/sun/star/sdb/CommandType.hpp>
33 #include <com/sun/star/sdb/DatabaseContext.hpp>
34 #include <com/sun/star/sdbc/XConnection.hpp>
35 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
36 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
37 #include <com/sun/star/sdbc/XRowSet.hpp>
38 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
39 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
40 #include <com/sun/star/awt/FontWeight.hpp>
41 #include <com/sun/star/awt/FontStrikeout.hpp>
42 #include <com/sun/star/awt/FontSlant.hpp>
43 #include <com/sun/star/awt/FontUnderline.hpp>
44 #include <com/sun/star/document/DocumentProperties.hpp>
45 #include <svtools/htmlkywd.hxx>
46 #include <svtools/rtfkeywd.hxx>
47 #include <tools/color.hxx>
48 #include <svtools/htmlout.hxx>
49 #include <sfx2/frmhtmlw.hxx>
50 #include <svl/numuno.hxx>
51 #include <vcl/svapp.hxx>
52 #include <UITools.hxx>
53 #include <toolkit/helper/vclunohelper.hxx>
54 #include <vcl/outdev.hxx>
55 #include <vcl/settings.hxx>
56 #include <svtools/rtfout.hxx>
57 #include <svtools/htmlcfg.hxx>
58 #include <connectivity/formattedcolumnvalue.hxx>
59 #include <memory>
60 
61 using namespace dbaui;
62 using namespace dbtools;
63 using namespace svx;
64 using namespace ::com::sun::star;
65 using namespace ::com::sun::star::uno;
66 using namespace ::com::sun::star::beans;
67 using namespace ::com::sun::star::container;
68 using namespace ::com::sun::star::sdbc;
69 using namespace ::com::sun::star::sdb;
70 using namespace ::com::sun::star::lang;
71 using namespace ::com::sun::star::sdbcx;
72 using namespace ::com::sun::star::awt;
73 using namespace ::com::sun::star::util;
74 
75 #define CELL_X                      1437
76 
ODatabaseImportExport(const svx::ODataAccessDescriptor & _aDataDescriptor,const Reference<XComponentContext> & _rM,const Reference<css::util::XNumberFormatter> & _rxNumberF)77 ODatabaseImportExport::ODatabaseImportExport(const svx::ODataAccessDescriptor& _aDataDescriptor,
78                                              const Reference< XComponentContext >& _rM,
79                                              const Reference< css::util::XNumberFormatter >& _rxNumberF)
80     :m_bBookmarkSelection( false )
81     ,m_xFormatter(_rxNumberF)
82     ,m_xContext(_rM)
83     ,m_nCommandType(CommandType::TABLE)
84     ,m_bNeedToReInitialize(false)
85     ,m_bInInitialize(false)
86     ,m_bCheckOnly(false)
87 {
88     m_eDestEnc = osl_getThreadTextEncoding();
89 
90     osl_atomic_increment( &m_refCount );
91     impl_initFromDescriptor( _aDataDescriptor, false );
92     osl_atomic_decrement( &m_refCount );
93 }
94 
95 // import data
ODatabaseImportExport(const::dbtools::SharedConnection & _rxConnection,const Reference<XNumberFormatter> & _rxNumberF,const Reference<XComponentContext> & _rM)96 ODatabaseImportExport::ODatabaseImportExport( const ::dbtools::SharedConnection& _rxConnection,
97         const Reference< XNumberFormatter >& _rxNumberF, const Reference< XComponentContext >& _rM )
98     :m_bBookmarkSelection( false )
99     ,m_pStream(nullptr)
100     ,m_xConnection(_rxConnection)
101     ,m_xFormatter(_rxNumberF)
102     ,m_xContext(_rM)
103     ,m_nCommandType(css::sdb::CommandType::TABLE)
104     ,m_bNeedToReInitialize(false)
105     ,m_bInInitialize(false)
106     ,m_bCheckOnly(false)
107 {
108     m_eDestEnc = osl_getThreadTextEncoding();
109 }
110 
~ODatabaseImportExport()111 ODatabaseImportExport::~ODatabaseImportExport()
112 {
113     acquire();
114     dispose();
115 }
116 
dispose()117 void ODatabaseImportExport::dispose()
118 {
119     // remove me as listener
120     Reference< XComponent >  xComponent(m_xConnection, UNO_QUERY);
121     if (xComponent.is())
122     {
123         Reference< XEventListener> xEvt(static_cast<cppu::OWeakObject*>(this),UNO_QUERY);
124         xComponent->removeEventListener(xEvt);
125     }
126     m_xConnection.clear();
127 
128     ::comphelper::disposeComponent(m_xRow);
129 
130     m_xObject.clear();
131     m_xResultSetMetaData.clear();
132     m_xResultSet.clear();
133     m_xRow.clear();
134     m_xRowLocate.clear();
135     m_xFormatter.clear();
136 }
137 
disposing(const EventObject & Source)138 void SAL_CALL ODatabaseImportExport::disposing( const EventObject& Source )
139 {
140     Reference<XConnection> xCon(Source.Source,UNO_QUERY);
141     if(m_xConnection.is() && m_xConnection == xCon)
142     {
143         m_xConnection.clear();
144         dispose();
145         m_bNeedToReInitialize = true;
146     }
147 }
148 
initialize(const ODataAccessDescriptor & _aDataDescriptor)149 void ODatabaseImportExport::initialize( const ODataAccessDescriptor& _aDataDescriptor )
150 {
151     impl_initFromDescriptor( _aDataDescriptor, true );
152 }
153 
impl_initFromDescriptor(const ODataAccessDescriptor & _aDataDescriptor,bool _bPlusDefaultInit)154 void ODatabaseImportExport::impl_initFromDescriptor( const ODataAccessDescriptor& _aDataDescriptor, bool _bPlusDefaultInit)
155 {
156     if ( !_bPlusDefaultInit )
157     {
158         m_sDataSourceName = _aDataDescriptor.getDataSource();
159         _aDataDescriptor[DataAccessDescriptorProperty::CommandType] >>= m_nCommandType;
160         _aDataDescriptor[DataAccessDescriptorProperty::Command]     >>= m_sName;
161         // some additional information
162         if(_aDataDescriptor.has(DataAccessDescriptorProperty::Connection))
163         {
164             Reference< XConnection > xPureConn( _aDataDescriptor[DataAccessDescriptorProperty::Connection], UNO_QUERY );
165             m_xConnection.reset( xPureConn, SharedConnection::NoTakeOwnership );
166             Reference< XEventListener> xEvt(static_cast<cppu::OWeakObject*>(this),UNO_QUERY);
167             Reference< XComponent >  xComponent(m_xConnection, UNO_QUERY);
168             if (xComponent.is() && xEvt.is())
169                 xComponent->addEventListener(xEvt);
170         }
171 
172         if ( _aDataDescriptor.has( DataAccessDescriptorProperty::Selection ) )
173             _aDataDescriptor[ DataAccessDescriptorProperty::Selection ] >>= m_aSelection;
174 
175         if ( _aDataDescriptor.has( DataAccessDescriptorProperty::BookmarkSelection ) )
176             _aDataDescriptor[ DataAccessDescriptorProperty::BookmarkSelection ] >>= m_bBookmarkSelection;
177 
178         if ( _aDataDescriptor.has( DataAccessDescriptorProperty::Cursor ) )
179         {
180             _aDataDescriptor[ DataAccessDescriptorProperty::Cursor ] >>= m_xResultSet;
181             m_xRowLocate.set( m_xResultSet, UNO_QUERY );
182         }
183 
184         if ( m_aSelection.hasElements() )
185         {
186             if ( !m_xResultSet.is() )
187             {
188                 SAL_WARN("dbaccess.ui", "ODatabaseImportExport::impl_initFromDescriptor: selection without result set is nonsense!" );
189                 m_aSelection.realloc( 0 );
190             }
191         }
192 
193         if ( m_aSelection.hasElements() )
194         {
195             if ( m_bBookmarkSelection && !m_xRowLocate.is() )
196             {
197                 SAL_WARN("dbaccess.ui", "ODatabaseImportExport::impl_initFromDescriptor: no XRowLocate -> no bookmarks!" );
198                 m_aSelection.realloc( 0 );
199             }
200         }
201     }
202     else
203         initialize();
204 }
205 
initialize()206 void ODatabaseImportExport::initialize()
207 {
208     m_bInInitialize = true;
209     m_bNeedToReInitialize = false;
210 
211     if ( !m_xConnection.is() )
212     {   // we need a connection
213         OSL_ENSURE(!m_sDataSourceName.isEmpty(),"There must be a datsource name!");
214         Reference<XNameAccess> xDatabaseContext( DatabaseContext::create(m_xContext), UNO_QUERY_THROW);
215         Reference< XEventListener> xEvt(static_cast<cppu::OWeakObject*>(this),UNO_QUERY);
216 
217         Reference< XConnection > xConnection;
218         SQLExceptionInfo aInfo = ::dbaui::createConnection( m_sDataSourceName, xDatabaseContext, m_xContext, xEvt, xConnection );
219         m_xConnection.reset( xConnection );
220 
221         if(aInfo.isValid() && aInfo.getType() == SQLExceptionInfo::TYPE::SQLException)
222             throw *static_cast<const SQLException*>(aInfo);
223     }
224 
225     Reference<XNameAccess> xNameAccess;
226     switch(m_nCommandType)
227     {
228         case CommandType::TABLE:
229             {
230                 // only for tables
231                 Reference<XTablesSupplier> xSup(m_xConnection,UNO_QUERY);
232                 if(xSup.is())
233                     xNameAccess = xSup->getTables();
234             }
235             break;
236         case CommandType::QUERY:
237             {
238                 Reference<XQueriesSupplier> xSup(m_xConnection,UNO_QUERY);
239                 if(xSup.is())
240                     xNameAccess = xSup->getQueries();
241             }
242             break;
243     }
244     if(xNameAccess.is() && xNameAccess->hasByName(m_sName))
245     {
246         xNameAccess->getByName(m_sName) >>= m_xObject;
247     }
248 
249     if(m_xObject.is())
250     {
251         try
252         {
253             if(m_xObject->getPropertySetInfo()->hasPropertyByName(PROPERTY_FONT))
254                 m_xObject->getPropertyValue(PROPERTY_FONT) >>= m_aFont;
255 
256             // the result set may be already set with the datadescriptor
257             if ( !m_xResultSet.is() )
258             {
259                 m_xResultSet.set( m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.sdb.RowSet", m_xContext), UNO_QUERY );
260                 Reference< XPropertySet > xProp( m_xResultSet, UNO_QUERY_THROW );
261                 xProp->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( m_xConnection.getTyped() ) );
262                 xProp->setPropertyValue( PROPERTY_COMMAND_TYPE, makeAny( m_nCommandType ) );
263                 xProp->setPropertyValue( PROPERTY_COMMAND, makeAny( m_sName ) );
264                 Reference< XRowSet > xRowSet( xProp, UNO_QUERY );
265                 xRowSet->execute();
266             }
267             if ( !m_xRow.is() && m_xResultSet.is() )
268             {
269                 m_xRow.set( m_xResultSet, UNO_QUERY );
270                 m_xRowLocate.set( m_xResultSet, UNO_QUERY );
271                 m_xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(m_xRow,UNO_QUERY_THROW)->getMetaData();
272                 Reference<XColumnsSupplier> xSup(m_xResultSet,UNO_QUERY_THROW);
273                 m_xRowSetColumns.set(xSup->getColumns(),UNO_QUERY_THROW);
274             }
275         }
276         catch(Exception& )
277         {
278             m_xRow = nullptr;
279             m_xResultSetMetaData = nullptr;
280             ::comphelper::disposeComponent(m_xResultSet);
281             throw;
282         }
283     }
284     if ( m_aFont.Name.isEmpty() )
285     {
286         vcl::Font aApplicationFont = OutputDevice::GetDefaultFont(
287             DefaultFontType::SANS_UNICODE,
288             Application::GetSettings().GetUILanguageTag().getLanguageType(),
289             GetDefaultFontFlags::OnlyOne
290         );
291         m_aFont = VCLUnoHelper::CreateFontDescriptor( aApplicationFont );
292     }
293 
294     m_bInInitialize = false;
295 }
296 
Write()297 bool ODatabaseImportExport::Write()
298 {
299     if ( m_bNeedToReInitialize )
300     {
301         if ( !m_bInInitialize )
302             initialize();
303     }
304     return true;
305 }
306 
Read()307 bool ODatabaseImportExport::Read()
308 {
309     if ( m_bNeedToReInitialize )
310     {
311         if ( !m_bInInitialize )
312             initialize();
313     }
314     return true;
315 }
316 
Write()317 bool ORTFImportExport::Write()
318 {
319     ODatabaseImportExport::Write();
320     m_pStream->WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RTF );
321     m_pStream->WriteCharPtr(OOO_STRING_SVTOOLS_RTF_ANSI);
322     if (sal_uInt32 nCpg = rtl_getWindowsCodePageFromTextEncoding(m_eDestEnc); nCpg && nCpg != 65001)
323     {
324         m_pStream->WriteCharPtr(OOO_STRING_SVTOOLS_RTF_ANSICPG).WriteUInt32AsString(nCpg);
325     }
326     m_pStream->WriteCharPtr(SAL_NEWLINE_STRING);
327 
328     bool bBold          = ( css::awt::FontWeight::BOLD     == m_aFont.Weight );
329     bool bItalic        = ( css::awt::FontSlant_ITALIC     == m_aFont.Slant );
330     bool bUnderline     = ( css::awt::FontUnderline::NONE  != m_aFont.Underline );
331     bool bStrikeout     = ( css::awt::FontStrikeout::NONE  != m_aFont.Strikeout );
332 
333     ::Color aColor;
334     if(m_xObject.is())
335         m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= aColor;
336 
337     OString aFonts(OUStringToOString(m_aFont.Name, RTL_TEXTENCODING_MS_1252));
338     if (aFonts.isEmpty())
339     {
340         OUString aName = Application::GetSettings().GetStyleSettings().GetAppFont().GetFamilyName();
341         aFonts = OUStringToOString(aName, RTL_TEXTENCODING_MS_1252);
342     }
343 
344     m_pStream->WriteCharPtr( "{\\fonttbl" );
345     if (!aFonts.isEmpty())
346     {
347         sal_Int32 nIdx{0};
348         sal_Int32 nTok{-1}; // to compensate pre-increment
349         do {
350             m_pStream->WriteCharPtr( "\\f" );
351             m_pStream->WriteInt32AsString(++nTok);
352             m_pStream->WriteCharPtr( "\\fcharset0\\fnil " );
353             m_pStream->WriteOString( aFonts.getToken(0, ';', nIdx) );
354             m_pStream->WriteChar( ';' );
355         } while (nIdx>=0);
356     }
357     m_pStream->WriteChar( '}' ) ;
358     m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
359     // write the rtf color table
360     m_pStream->WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_COLORTBL ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RED );
361     m_pStream->WriteUInt32AsString(aColor.GetRed());
362     m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_GREEN );
363     m_pStream->WriteUInt32AsString(aColor.GetGreen());
364     m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_BLUE );
365     m_pStream->WriteUInt32AsString(aColor.GetBlue());
366 
367     m_pStream->WriteCharPtr( ";\\red255\\green255\\blue255;\\red192\\green192\\blue192;}" )
368                 .WriteCharPtr( SAL_NEWLINE_STRING );
369 
370     static char const aCell1[] = "\\clbrdrl\\brdrs\\brdrcf0\\clbrdrt\\brdrs\\brdrcf0\\clbrdrb\\brdrs\\brdrcf0\\clbrdrr\\brdrs\\brdrcf0\\clshdng10000\\clcfpat2\\cellx";
371 
372     m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TROWD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TRGAPH );
373     m_pStream->WriteInt32AsString(40);
374     m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
375 
376     if(m_xObject.is())
377     {
378         Reference<XColumnsSupplier> xColSup(m_xObject,UNO_QUERY);
379         Reference<XNameAccess> xColumns = xColSup->getColumns();
380         Sequence< OUString> aNames(xColumns->getElementNames());
381         const OUString* pIter = aNames.getConstArray();
382 
383         sal_Int32 nCount = aNames.getLength();
384         bool bUseResultMetaData = false;
385         if ( !nCount )
386         {
387             nCount = m_xResultSetMetaData->getColumnCount();
388             bUseResultMetaData = true;
389         }
390 
391         for( sal_Int32 i=1; i<=nCount; ++i )
392         {
393             m_pStream->WriteCharPtr( aCell1 );
394             m_pStream->WriteInt32AsString(i*CELL_X);
395             m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
396         }
397 
398         // column description
399         m_pStream->WriteChar( '{' ).WriteCharPtr( SAL_NEWLINE_STRING );
400         m_pStream->WriteCharPtr( "\\trrh-270\\pard\\intbl" );
401 
402         std::unique_ptr<OString[]> pHorzChar(new OString[nCount]);
403 
404         for ( sal_Int32 i=1; i <= nCount; ++i )
405         {
406             sal_Int32 nAlign = 0;
407             OUString sColumnName;
408             if ( bUseResultMetaData )
409                 sColumnName = m_xResultSetMetaData->getColumnName(i);
410             else
411             {
412                 sColumnName = *pIter;
413                 Reference<XPropertySet> xColumn;
414                 xColumns->getByName(sColumnName) >>= xColumn;
415                 xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign;
416                 ++pIter;
417             }
418 
419             const char* pChar;
420             switch( nAlign )
421             {
422                 case 1: pChar = OOO_STRING_SVTOOLS_RTF_QC;  break;
423                 case 2: pChar = OOO_STRING_SVTOOLS_RTF_QR;  break;
424                 case 0:
425                 default:pChar = OOO_STRING_SVTOOLS_RTF_QL;  break;
426             }
427 
428             pHorzChar[i-1] = pChar; // to avoid to always rummage in the ITEMSET later on
429 
430             m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
431             m_pStream->WriteChar( '{' );
432             m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_QC );   // column header always centered
433 
434             if ( bBold )        m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_B );
435             if ( bItalic )      m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_I );
436             if ( bUnderline )   m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_UL );
437             if ( bStrikeout )   m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_STRIKE );
438 
439             m_pStream->WriteCharPtr( "\\fs20\\f0\\cf0\\cb2" );
440             m_pStream->WriteChar( ' ' );
441             RTFOutFuncs::Out_String(*m_pStream, sColumnName, m_eDestEnc);
442 
443             m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CELL );
444             m_pStream->WriteChar( '}' );
445             m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
446             m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PARD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_INTBL );
447         }
448 
449         m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ROW );
450         m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ).WriteChar( '}' );
451         m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
452 
453         sal_Int32 k=1;
454         sal_Int32 kk=0;
455         if ( m_aSelection.hasElements() )
456         {
457             const Any* pSelIter = m_aSelection.getConstArray();
458             const Any* pEnd   = pSelIter + m_aSelection.getLength();
459 
460             bool bContinue = true;
461             for( ; pSelIter != pEnd && bContinue; ++pSelIter )
462             {
463                 if ( m_bBookmarkSelection )
464                 {
465                     bContinue = m_xRowLocate->moveToBookmark( *pSelIter );
466                 }
467                 else
468                 {
469                     sal_Int32 nPos = -1;
470                     OSL_VERIFY( *pSelIter >>= nPos );
471                     bContinue = ( m_xResultSet->absolute( nPos ) );
472                 }
473 
474                 if ( bContinue )
475                     appendRow( pHorzChar.get(), nCount, k, kk );
476             }
477         }
478         else
479         {
480             m_xResultSet->beforeFirst(); // set back before the first row
481             while(m_xResultSet->next())
482             {
483                 appendRow(pHorzChar.get(),nCount,k,kk);
484             }
485         }
486     }
487 
488     m_pStream->WriteChar( '}' ).WriteCharPtr( SAL_NEWLINE_STRING );
489     m_pStream->WriteUChar( 0 );
490     return ((*m_pStream).GetError() == ERRCODE_NONE);
491 }
492 
appendRow(OString const * pHorzChar,sal_Int32 _nColumnCount,sal_Int32 & k,sal_Int32 & kk)493 void ORTFImportExport::appendRow(OString const * pHorzChar,sal_Int32 _nColumnCount,sal_Int32& k,sal_Int32& kk)
494 {
495     ++kk;
496     m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TROWD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TRGAPH );
497     m_pStream->WriteInt32AsString(40);
498     m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
499 
500     static char const aCell2[] = "\\clbrdrl\\brdrs\\brdrcf2\\clbrdrt\\brdrs\\brdrcf2\\clbrdrb\\brdrs\\brdrcf2\\clbrdrr\\brdrs\\brdrcf2\\clshdng10000\\clcfpat1\\cellx";
501 
502     for ( sal_Int32 i=1; i<=_nColumnCount; ++i )
503     {
504         m_pStream->WriteCharPtr( aCell2 );
505         m_pStream->WriteInt32AsString(i*CELL_X);
506         m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
507     }
508 
509     const bool bBold            = ( css::awt::FontWeight::BOLD     == m_aFont.Weight );
510     const bool bItalic      = ( css::awt::FontSlant_ITALIC     == m_aFont.Slant );
511     const bool bUnderline       = ( css::awt::FontUnderline::NONE  != m_aFont.Underline );
512     const bool bStrikeout       = ( css::awt::FontStrikeout::NONE  != m_aFont.Strikeout );
513     Reference< XRowSet > xRowSet(m_xRow,UNO_QUERY);
514 
515     m_pStream->WriteChar( '{' );
516     m_pStream->WriteCharPtr( "\\trrh-270\\pard\\intbl" );
517     for ( sal_Int32 i=1; i <= _nColumnCount; ++i )
518     {
519         m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
520         m_pStream->WriteChar( '{' );
521         m_pStream->WriteOString( pHorzChar[i-1] );
522 
523         if ( bBold )        m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_B );
524         if ( bItalic )      m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_I );
525         if ( bUnderline )   m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_UL );
526         if ( bStrikeout )   m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_STRIKE );
527 
528         m_pStream->WriteCharPtr( "\\fs20\\f1\\cf0\\cb1 " );
529 
530         try
531         {
532             Reference<XPropertySet> xColumn(m_xRowSetColumns->getByIndex(i-1),UNO_QUERY_THROW);
533             dbtools::FormattedColumnValue aFormatedValue(m_xContext,xRowSet,xColumn);
534             OUString sValue = aFormatedValue.getFormattedValue();
535             if ( !sValue.isEmpty() )
536                 RTFOutFuncs::Out_String(*m_pStream,sValue,m_eDestEnc);
537         }
538         catch (Exception&)
539         {
540             SAL_WARN("dbaccess.ui","RTF WRITE!");
541         }
542 
543         m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CELL );
544         m_pStream->WriteChar( '}' );
545         m_pStream->WriteCharPtr( SAL_NEWLINE_STRING );
546         m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PARD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_INTBL );
547     }
548     m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ROW ).WriteCharPtr( SAL_NEWLINE_STRING );
549     m_pStream->WriteChar( '}' );
550     ++k;
551 }
552 
Read()553 bool ORTFImportExport::Read()
554 {
555     ODatabaseImportExport::Read();
556     SvParserState eState = SvParserState::Error;
557     if ( m_pStream )
558     {
559         tools::SvRef<ORTFReader> xReader(new ORTFReader((*m_pStream),m_xConnection,m_xFormatter,m_xContext));
560         if ( isCheckEnabled() )
561             xReader->enableCheckOnly();
562         eState = xReader->CallParser();
563     }
564 
565     return eState != SvParserState::Error;
566 }
567 
568 const sal_Int16 OHTMLImportExport::nCellSpacing = 0;
569 const char OHTMLImportExport::sIndentSource[nIndentMax+1] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
570 
571 // Macros for HTML-Export
572 #define TAG_ON( tag )       HTMLOutFuncs::Out_AsciiTag( (*m_pStream), tag )
573 #define TAG_OFF( tag )      HTMLOutFuncs::Out_AsciiTag( (*m_pStream), tag, false )
574 #define OUT_LF()            m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() )
575 #define TAG_ON_LF( tag )    (TAG_ON( tag ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() ))
576 #define TAG_OFF_LF( tag )   (TAG_OFF( tag ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() ))
577 
OHTMLImportExport(const svx::ODataAccessDescriptor & _aDataDescriptor,const Reference<XComponentContext> & _rM,const Reference<css::util::XNumberFormatter> & _rxNumberF)578 OHTMLImportExport::OHTMLImportExport(const svx::ODataAccessDescriptor& _aDataDescriptor,
579                                      const Reference< XComponentContext >& _rM,
580                                      const Reference< css::util::XNumberFormatter >& _rxNumberF)
581         : ODatabaseImportExport(_aDataDescriptor,_rM,_rxNumberF)
582     ,m_nIndent(0)
583 #if OSL_DEBUG_LEVEL > 0
584     ,m_bCheckFont(false)
585 #endif
586 {
587     // set HTML configuration
588     SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
589     m_eDestEnc = rHtmlOptions.GetTextEncoding();
590     strncpy( sIndent, sIndentSource ,std::min(sizeof(sIndent),sizeof(sIndentSource)));
591     sIndent[0] = 0;
592 }
593 
Write()594 bool OHTMLImportExport::Write()
595 {
596     ODatabaseImportExport::Write();
597     if(m_xObject.is())
598     {
599         m_pStream->WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype40 ).WriteChar( '>' ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( SAL_NEWLINE_STRING );
600         TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_html );
601         WriteHeader();
602         OUT_LF();
603         WriteBody();
604         OUT_LF();
605         TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_html );
606 
607         return ((*m_pStream).GetError() == ERRCODE_NONE);
608     }
609     return false;
610 }
611 
Read()612 bool OHTMLImportExport::Read()
613 {
614     ODatabaseImportExport::Read();
615     SvParserState eState = SvParserState::Error;
616     if ( m_pStream )
617     {
618         tools::SvRef<OHTMLReader> xReader(new OHTMLReader((*m_pStream),m_xConnection,m_xFormatter,m_xContext));
619         if ( isCheckEnabled() )
620             xReader->enableCheckOnly();
621         xReader->SetTableName(m_sDefaultTableName);
622         eState = xReader->CallParser();
623     }
624 
625     return eState != SvParserState::Error;
626 }
627 
WriteHeader()628 void OHTMLImportExport::WriteHeader()
629 {
630     uno::Reference<document::XDocumentProperties> xDocProps(
631         document::DocumentProperties::create( m_xContext ) );
632     if (xDocProps.is()) {
633         xDocProps->setTitle(m_sName);
634     }
635 
636     IncIndent(1); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_head );
637 
638     SfxFrameHTMLWriter::Out_DocInfo( (*m_pStream), OUString(),
639         xDocProps, sIndent, osl_getThreadTextEncoding() );
640     OUT_LF();
641     IncIndent(-1); OUT_LF(); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_head );
642 }
643 
WriteBody()644 void OHTMLImportExport::WriteBody()
645 {
646     IncIndent(1);
647     m_pStream->WriteCharPtr( "<" ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_style ).WriteCharPtr( " " ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_type ).WriteCharPtr( "=\"text/css\">" );
648 
649     m_pStream->WriteCharPtr( "<!-- " ); OUT_LF();
650     m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body ).WriteCharPtr( " { " ).WriteCharPtr( "font-family: " ).WriteChar( '"' ).WriteOString( OUStringToOString(m_aFont.Name, osl_getThreadTextEncoding()) ).WriteChar( '\"' );
651         // TODO : think about the encoding of the font name
652     m_pStream->WriteCharPtr( "; " ).WriteCharPtr( "font-size: " );
653     m_pStream->WriteInt32AsString(m_aFont.Height);
654     m_pStream->WriteChar( '}' );
655 
656     OUT_LF();
657     m_pStream->WriteCharPtr( " -->" );
658     IncIndent(-1); OUT_LF(); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_style );
659     OUT_LF();
660 
661     // default Textcolour black
662     m_pStream->WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_text ).WriteChar( '=' );
663     ::Color aColor;
664     if(m_xObject.is())
665         m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= aColor;
666     HTMLOutFuncs::Out_Color( (*m_pStream), aColor );
667 
668     m_pStream->WriteCharPtr( " " OOO_STRING_SVTOOLS_HTML_O_bgcolor "=" );
669     HTMLOutFuncs::Out_Color( (*m_pStream), aColor );
670 
671     m_pStream->WriteChar( '>' ); OUT_LF();
672 
673     WriteTables();
674 
675     TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_body );
676 }
677 
WriteTables()678 void OHTMLImportExport::WriteTables()
679 {
680     OString aStrOut  = OOO_STRING_SVTOOLS_HTML_table
681             " "
682             OOO_STRING_SVTOOLS_HTML_frame
683             "="
684             OOO_STRING_SVTOOLS_HTML_TF_void;
685 
686     Sequence< OUString> aNames;
687     Reference<XNameAccess> xColumns;
688     bool bUseResultMetaData = false;
689     if(m_xObject.is())
690     {
691         Reference<XColumnsSupplier> xColSup(m_xObject,UNO_QUERY);
692         xColumns = xColSup->getColumns();
693         aNames = xColumns->getElementNames();
694         if ( !aNames.hasElements() )
695         {
696             sal_Int32 nCount = m_xResultSetMetaData->getColumnCount();
697             aNames.realloc(nCount);
698             for (sal_Int32 i= 0; i < nCount; ++i)
699                 aNames[i] = m_xResultSetMetaData->getColumnName(i+1);
700             bUseResultMetaData = true;
701         }
702     }
703 
704     aStrOut += " "
705             OOO_STRING_SVTOOLS_HTML_O_align
706             "="
707             OOO_STRING_SVTOOLS_HTML_AL_left
708             " "
709             OOO_STRING_SVTOOLS_HTML_O_cellspacing
710             "=" +
711             OString::number(nCellSpacing) +
712             " "
713             OOO_STRING_SVTOOLS_HTML_O_cols
714             "=" +
715             OString::number(aNames.getLength()) +
716             " "
717             OOO_STRING_SVTOOLS_HTML_O_border
718             "=1";
719 
720     IncIndent(1);
721     TAG_ON( aStrOut.getStr() );
722 
723     FontOn();
724 
725     TAG_ON( OOO_STRING_SVTOOLS_HTML_caption );
726     TAG_ON( OOO_STRING_SVTOOLS_HTML_bold );
727 
728     m_pStream->WriteOString( OUStringToOString(m_sName, osl_getThreadTextEncoding()) );
729         // TODO : think about the encoding of the name
730     TAG_OFF( OOO_STRING_SVTOOLS_HTML_bold );
731     TAG_OFF( OOO_STRING_SVTOOLS_HTML_caption );
732 
733     FontOff();
734     OUT_LF();
735     // </FONT>
736 
737     IncIndent(1);
738     TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_thead );
739 
740     IncIndent(1);
741     TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tablerow );
742 
743     if(m_xObject.is())
744     {
745         std::unique_ptr<sal_Int32[]> pFormat(new sal_Int32[aNames.getLength()]);
746 
747         std::unique_ptr<const char *[]> pHorJustify(new const char*[aNames.getLength()]);
748         std::unique_ptr<sal_Int32[]> pColWidth(new sal_Int32[aNames.getLength()]);
749 
750         sal_Int32 nHeight = 0;
751         m_xObject->getPropertyValue(PROPERTY_ROW_HEIGHT) >>= nHeight;
752 
753         // 1. writing the column description
754         const OUString* pIter = aNames.getConstArray();
755         const OUString* pEnd = pIter + aNames.getLength();
756 
757         for( sal_Int32 i=0;pIter != pEnd; ++pIter,++i )
758         {
759             sal_Int32 nAlign = 0;
760             pFormat[i] = 0;
761             pColWidth[i] = 100;
762             if ( !bUseResultMetaData )
763             {
764                 Reference<XPropertySet> xColumn;
765                 xColumns->getByName(*pIter) >>= xColumn;
766                 xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign;
767                 pFormat[i] = ::comphelper::getINT32(xColumn->getPropertyValue(PROPERTY_FORMATKEY));
768                 pColWidth[i] = ::comphelper::getINT32(xColumn->getPropertyValue(PROPERTY_WIDTH));
769             }
770 
771             switch( nAlign )
772             {
773                 case 1:     pHorJustify[i] = OOO_STRING_SVTOOLS_HTML_AL_center; break;
774                 case 2:     pHorJustify[i] = OOO_STRING_SVTOOLS_HTML_AL_right;  break;
775                 default:    pHorJustify[i] = OOO_STRING_SVTOOLS_HTML_AL_left;       break;
776             }
777 
778             if(i == aNames.getLength()-1)
779                 IncIndent(-1);
780 
781             WriteCell(pFormat[i],pColWidth[i],nHeight,pHorJustify[i],*pIter,OOO_STRING_SVTOOLS_HTML_tableheader);
782         }
783 
784         IncIndent(-1);
785         TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tablerow );
786         TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_thead );
787 
788         IncIndent(1);
789         TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tbody );
790 
791         // 2. and now the data
792         Reference< XRowSet > xRowSet(m_xRow,UNO_QUERY);
793         sal_Int32 kk=0;
794         m_xResultSet->beforeFirst(); // set back before the first row
795         while(m_xResultSet->next())
796         {
797             IncIndent(1);
798             TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tablerow );
799 
800             ++kk;
801             for(sal_Int32 i=1;i<=aNames.getLength();++i)
802             {
803                 if(i == aNames.getLength())
804                     IncIndent(-1);
805 
806                 OUString aValue;
807                 try
808                 {
809                     Reference<XPropertySet> xColumn(m_xRowSetColumns->getByIndex(i-1),UNO_QUERY_THROW);
810                     dbtools::FormattedColumnValue aFormatedValue(m_xContext,xRowSet,xColumn);
811                     OUString sValue = aFormatedValue.getFormattedValue();
812                     if (!sValue.isEmpty())
813                     {
814                         aValue = sValue;
815                     }
816                 }
817                 catch( const Exception& )
818                 {
819                     DBG_UNHANDLED_EXCEPTION("dbaccess");
820                 }
821                 WriteCell(pFormat[i-1],pColWidth[i-1],nHeight,pHorJustify[i-1],aValue,OOO_STRING_SVTOOLS_HTML_tabledata);
822             }
823             TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tablerow );
824         }
825     }
826     else
827     {
828         IncIndent(-1);
829         TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tablerow );
830         TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_thead );
831 
832         IncIndent(1);
833         TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tbody );
834     }
835 
836     IncIndent(-1); OUT_LF(); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tbody );
837     IncIndent(-1); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_table );
838 }
839 
WriteCell(sal_Int32 nFormat,sal_Int32 nWidthPixel,sal_Int32 nHeightPixel,const char * pChar,const OUString & rValue,const char * pHtmlTag)840 void OHTMLImportExport::WriteCell( sal_Int32 nFormat, sal_Int32 nWidthPixel, sal_Int32 nHeightPixel, const char* pChar,
841                                    const OUString& rValue, const char* pHtmlTag)
842 {
843     OString aStrTD = pHtmlTag;
844 
845     nWidthPixel  = nWidthPixel  ? nWidthPixel   : 86;
846     nHeightPixel = nHeightPixel ? nHeightPixel  : 17;
847 
848     // despite the <TABLE COLS=n> and <COL WIDTH=x> designation necessary,
849     // as Netscape is not paying attention to them.
850     // column width
851     aStrTD += " "
852             OOO_STRING_SVTOOLS_HTML_O_width
853             "=" +
854             OString::number(nWidthPixel) +
855     // line height
856             " "
857             OOO_STRING_SVTOOLS_HTML_O_height
858             "=" +
859             OString::number(nHeightPixel) +
860             " "
861             OOO_STRING_SVTOOLS_HTML_O_align
862             "=" +
863             pChar;
864 
865     SvNumberFormatsSupplierObj* pSupplierImpl = m_xFormatter.is() ? comphelper::getUnoTunnelImplementation<SvNumberFormatsSupplierObj>(m_xFormatter->getNumberFormatsSupplier()) : nullptr;
866     SvNumberFormatter* pFormatter = pSupplierImpl ? pSupplierImpl->GetNumberFormatter() : nullptr;
867     if(pFormatter)
868     {
869         double fVal = 0.0;
870 
871         try
872         {
873             fVal = m_xFormatter->convertStringToNumber(nFormat,rValue);
874             HTMLOutFuncs::CreateTableDataOptionsValNum(false, fVal,nFormat, *pFormatter);
875         }
876         catch(const Exception&)
877         {
878             HTMLOutFuncs::CreateTableDataOptionsValNum(false, fVal,nFormat, *pFormatter);
879         }
880     }
881 
882     TAG_ON( aStrTD.getStr() );
883 
884     FontOn();
885 
886     bool bBold          = ( css::awt::FontWeight::BOLD     == m_aFont.Weight );
887     bool bItalic        = ( css::awt::FontSlant_ITALIC     == m_aFont.Slant );
888     bool bUnderline     = ( css::awt::FontUnderline::NONE  != m_aFont.Underline );
889     bool bStrikeout     = ( css::awt::FontStrikeout::NONE  != m_aFont.Strikeout );
890 
891     if ( bBold )        TAG_ON( OOO_STRING_SVTOOLS_HTML_bold );
892     if ( bItalic )      TAG_ON( OOO_STRING_SVTOOLS_HTML_italic );
893     if ( bUnderline )   TAG_ON( OOO_STRING_SVTOOLS_HTML_underline );
894     if ( bStrikeout )   TAG_ON( OOO_STRING_SVTOOLS_HTML_strike );
895 
896     if ( rValue.isEmpty() )
897         TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak );        // no completely empty cell
898     else
899         HTMLOutFuncs::Out_String( (*m_pStream), rValue ,m_eDestEnc);
900 
901     if ( bStrikeout )   TAG_OFF( OOO_STRING_SVTOOLS_HTML_strike );
902     if ( bUnderline )   TAG_OFF( OOO_STRING_SVTOOLS_HTML_underline );
903     if ( bItalic )      TAG_OFF( OOO_STRING_SVTOOLS_HTML_italic );
904     if ( bBold )        TAG_OFF( OOO_STRING_SVTOOLS_HTML_bold );
905 
906     FontOff();
907 
908     TAG_OFF_LF( pHtmlTag );
909 }
910 
FontOn()911 void OHTMLImportExport::FontOn()
912 {
913 #if OSL_DEBUG_LEVEL > 0
914     m_bCheckFont = true;
915 #endif
916 
917     // <FONT FACE="xxx">
918     OString aStrOut  = "<"
919             OOO_STRING_SVTOOLS_HTML_font
920             " "
921             OOO_STRING_SVTOOLS_HTML_O_face
922             "="
923             "\"" +
924             OUStringToOString(m_aFont.Name,osl_getThreadTextEncoding()) +
925         // TODO : think about the encoding of the font name
926             "\""
927             " "
928             OOO_STRING_SVTOOLS_HTML_O_color
929             "=";
930     m_pStream->WriteOString( aStrOut );
931 
932     ::Color aColor;
933     if(m_xObject.is())
934         m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= aColor;
935 
936     HTMLOutFuncs::Out_Color( (*m_pStream), aColor );
937     m_pStream->WriteCharPtr( ">" );
938 }
939 
FontOff()940 inline void OHTMLImportExport::FontOff()
941 {
942 #if OSL_DEBUG_LEVEL > 0
943     OSL_ENSURE(m_bCheckFont,"No FontOn() called");
944 #endif
945     TAG_OFF( OOO_STRING_SVTOOLS_HTML_font );
946 #if OSL_DEBUG_LEVEL > 0
947     m_bCheckFont = false;
948 #endif
949 }
950 
IncIndent(sal_Int16 nVal)951 void OHTMLImportExport::IncIndent( sal_Int16 nVal )
952 {
953     sIndent[m_nIndent] = '\t';
954     m_nIndent = m_nIndent + nVal;
955     if ( m_nIndent < 0 )
956         m_nIndent = 0;
957     else if ( m_nIndent > nIndentMax )
958         m_nIndent = nIndentMax;
959     sIndent[m_nIndent] = 0;
960 }
961 
962 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
963