~ubuntu-branches/ubuntu/breezy/koffice/breezy-security

« back to all changes in this revision

Viewing changes to filters/kspread/html/htmlexport.cc

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2005-10-11 14:49:50 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051011144950-lwpngbifzp8nk0ds
Tags: 1:1.4.1-0ubuntu7
* SECURITY UPDATE: fix heap based buffer overflow in the RTF importer of KWord
* Opening specially crafted RTF files in KWord can cause
  execution of abitrary code.
* Add kubuntu_01_rtfimport_heap_overflow.diff
* References:
  CAN-2005-2971
  CESA-2005-005
  http://www.koffice.org/security/advisory-20051011-1.txt

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* This file is part of the KDE project
2
2
   Copyright (C) 2001 Eva Brucherseifer <eva@kde.org>
 
3
   Copyright (C) 2005 Bram Schoenmakers <bramschoenmakers@kde.nl>
3
4
   based on kspread csv export filter by David Faure
4
5
 
5
6
   This library is free software; you can redistribute it and/or
19
20
*/
20
21
 
21
22
#include <htmlexport.h>
 
23
#include <exportdialog.h>
22
24
 
23
 
#include <qregexp.h>
24
25
#include <qfile.h>
 
26
#include <qtextcodec.h>
25
27
 
26
28
#include <kdebug.h>
27
29
#include <kgenericfactory.h>
28
30
#include <koFilterChain.h>
29
31
#include <koDocumentInfo.h>
 
32
#include <kofficeversion.h>
30
33
 
31
34
#include <kspread_map.h>
32
35
#include <kspread_sheet.h>
33
36
#include <kspread_doc.h>
34
37
 
35
38
typedef KGenericFactory<HTMLExport, KoFilter> HTMLExportFactory;
36
 
K_EXPORT_COMPONENT_FACTORY( libkspreadhtmlexport, HTMLExportFactory( "htmlexport" ) )
 
39
K_EXPORT_COMPONENT_FACTORY( libkspreadhtmlexport, HTMLExportFactory( "kofficefilters" ) )
37
40
 
38
41
class Cell {
39
42
 public:
49
52
    }
50
53
};
51
54
 
 
55
const QString html_table_tag = "table";
 
56
const QString html_table_options = QString(" border=\"%1\" cellspacing=\"%2\"");
 
57
const QString html_row_tag = "tr";
 
58
const QString html_row_options = "";
 
59
const QString html_cell_tag = "td";
 
60
const QString html_cell_options = "";
 
61
const QString html_bold = "b";
 
62
const QString html_italic = "i";
 
63
const QString html_underline = "u";
 
64
const QString html_right= "right";
 
65
const QString html_left= "left";
 
66
const QString html_center= "center";
 
67
const QString html_top="top";
 
68
const QString html_bottom="bottom";
 
69
const QString html_middle="middle";
 
70
const QString html_h1="h1";
52
71
 
53
72
HTMLExport::HTMLExport(KoFilter *, const char *, const QStringList&) :
54
 
                     KoFilter() {
 
73
    KoFilter(), m_dialog( new ExportDialog() )
 
74
{
 
75
}
 
76
 
 
77
HTMLExport::~HTMLExport()
 
78
{
 
79
  delete m_dialog;
55
80
}
56
81
 
57
82
// HTML enitities, AFAIK we don't need to escape " to &quot; (dnaber):
59
84
const QString nbsp ("&nbsp;");
60
85
const QString strLt  ("&lt;");
61
86
const QString strGt  ("&gt;");
62
 
const QRegExp regExpAmp ("&");
63
 
const QRegExp regExpLt  ("<");
64
 
const QRegExp regExpGt  (">");
65
 
const QRegExp regExpSpace(" ");
66
87
 
67
88
// The reason why we use the KoDocument* approach and not the QDomDocument
68
89
// approach is because we don't want to export formulas but values !
69
90
KoFilter::ConversionStatus HTMLExport::convert( const QCString& from, const QCString& to )
70
91
{
 
92
    if(to!="text/html" || from!="application/x-kspread")
 
93
    {
 
94
      kdWarning(30501) << "Invalid mimetypes " << to << " " << from << endl;
 
95
      return KoFilter::NotImplemented;
 
96
    }
 
97
 
71
98
    KoDocument* document = m_chain->inputDocument();
72
 
    QString file( m_chain->outputFile() );
 
99
 
73
100
    if ( !document )
74
 
        return KoFilter::StupidError;
 
101
      return KoFilter::StupidError;
75
102
 
76
103
    if(strcmp(document->className(), "KSpreadDoc")!=0)  // it's safer that way :)
77
104
    {
78
 
        kdWarning(30501) << "document isn't a KSpreadDoc but a " << document->className() << endl;
79
 
        return KoFilter::NotImplemented;
80
 
    }
81
 
    if(to!="text/html" || from!="application/x-kspread")
82
 
    {
83
 
        kdWarning(30501) << "Invalid mimetypes " << to << " " << from << endl;
84
 
        return KoFilter::NotImplemented;
 
105
      kdWarning(30501) << "document isn't a KSpreadDoc but a " << document->className() << endl;
 
106
      return KoFilter::NotImplemented;
85
107
    }
86
108
 
87
109
    const KSpreadDoc * ksdoc=static_cast<const KSpreadDoc *>(document);
88
110
 
89
111
    if( ksdoc->mimeType() != "application/x-kspread" )
90
112
    {
91
 
        kdWarning(30501) << "Invalid document mimetype " << ksdoc->mimeType() << endl;
92
 
        return KoFilter::NotImplemented;
93
 
    }
94
 
 
95
 
    QString html_table_tag = "table";
96
 
    QString html_table_options = " border=\"1\"";
97
 
    QString html_row_tag = "tr";
98
 
    QString html_row_options = "";
99
 
    QString html_cell_tag = "td";
100
 
    QString html_cell_options = "";
101
 
    QString html_bold = "b";
102
 
    QString html_italic = "i";
103
 
    QString html_underline = "u";
104
 
    QString html_right= "right";
105
 
    QString html_left= "left";
106
 
    QString html_center= "center";
107
 
    QString html_top="top";
108
 
    QString html_bottom="bottom";
109
 
    QString html_middle="middle";
110
 
 
111
 
    // Ah ah ah - the document is const, but the map and table aren't. Safety:0.
 
113
      kdWarning(30501) << "Invalid document mimetype " << ksdoc->mimeType() << endl;
 
114
      return KoFilter::NotImplemented;
 
115
    }
 
116
 
 
117
    KSpreadSheet *sheet = ksdoc->map()->firstSheet();
 
118
    QString filenameBase = m_chain->outputFile();
 
119
    filenameBase = filenameBase.left( filenameBase.findRev( '.' ) );
 
120
 
 
121
    QStringList sheets;
 
122
    while( sheet != 0 )
 
123
    {
 
124
      int rows = 0;
 
125
      int columns = 0;
 
126
      detectFilledCells( sheet, rows, columns );
 
127
      m_rowmap[ sheet->sheetName() ] = rows;
 
128
      m_columnmap[ sheet->sheetName() ] = columns;
 
129
 
 
130
      if( rows > 0 && columns > 0 )
 
131
      {
 
132
        sheets.append( sheet->sheetName() );
 
133
      }
 
134
      sheet = ksdoc->map()->nextSheet();
 
135
    }
 
136
    m_dialog->setSheets( sheets );
 
137
 
 
138
    if( m_dialog->exec() == QDialog::Rejected )
 
139
      return KoFilter::UserCancelled;
 
140
 
 
141
    sheets = m_dialog->sheets();
112
142
    QString str;
113
 
    QString emptyLines;
114
 
 
115
 
    QString title;
116
 
    KoDocumentInfo *info = document->documentInfo();
117
 
    KoDocumentInfoAbout *aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
118
 
    if ( aboutPage && !aboutPage->title().isEmpty() )
119
 
      title = aboutPage->title();
120
 
    else
121
 
      title = file;
122
 
 
123
 
    // Now get hold of the table to export
124
 
    // (Hey, this could be part of the dialog too, choosing which table to export....
125
 
    //  It's great to have parametrable filters... IIRC even MSOffice doesn't have that)
126
 
    // Ok, for now we'll use the first table - my document has only one table anyway ;-)))
127
 
    KSpreadTable * table = ksdoc->map()->firstTable();
128
 
 
129
 
    // header
130
 
    str = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" ";
131
 
    str += " \"http://www.w3.org/TR/html4/loose.dtd\"> \n";
132
 
    str += "<html>\n";
133
 
    str += "<head>\n";
134
 
    // TODO: possibility of choosing other encodings
135
 
    str += "<meta http-equiv=\"Content-Type\" ";
136
 
    str += "content=\"text/html; charset=UTF-8\">\n";
137
 
    str += "<meta name=\"Generator\" ";
138
 
    str += "content=\"KSpread HTML Export Filter Version = 0.2\">\n";
139
 
    // I have no idea where to get the document name from :-(  table->tableName()
140
 
    str += "<title>" + title + "</title>\n";
141
 
    str += "</head>\n";
142
 
    str += QString("<body bgcolor=\"#FFFFFF\" dir=\"%1\">\n").arg(
143
 
        table->isRightToLeft()?"rtl":"ltr");
144
 
 
145
 
    while (table != 0)
 
143
    for( uint i = 0; i < sheets.count() ; ++i )
146
144
    {
147
 
 
148
 
      // Either we get hold of KSpreadTable::m_dctCells and apply the old method below (for sorting)
 
145
      sheet = ksdoc->map()->findSheet( sheets[i] );
 
146
 
 
147
      QString file = fileName( filenameBase, sheet->sheetName(), sheets.count() > 1 );
 
148
 
 
149
      if( m_dialog->separateFiles() || sheets[i] == sheets.first() )
 
150
      {
 
151
        str = QString::null;
 
152
        openPage( sheet, document, str );
 
153
        writeTOC( sheets, filenameBase, str );
 
154
      }
 
155
 
 
156
      convertSheet( sheet, str, m_rowmap[ sheet->sheetName() ], m_columnmap[ sheet->sheetName() ] );
 
157
 
 
158
      if( m_dialog->separateFiles() || sheets[i] == sheets.last() )
 
159
      {
 
160
        closePage( str );
 
161
        QFile out(file);
 
162
        if(!out.open(IO_WriteOnly)) {
 
163
          kdError(30501) << "Unable to open output file!" << endl;
 
164
          out.close();
 
165
          return KoFilter::FileNotFound;
 
166
        }
 
167
        QTextStream streamOut(&out);
 
168
        streamOut.setCodec( m_dialog->encoding() );
 
169
        streamOut << str << endl;
 
170
        out.close();
 
171
      }
 
172
 
 
173
      if( !m_dialog->separateFiles() )
 
174
      {
 
175
        createSheetSeparator( str );
 
176
      }
 
177
 
 
178
    }
 
179
 
 
180
    emit sigProgress(100);
 
181
    return KoFilter::OK;
 
182
}
 
183
 
 
184
void HTMLExport::openPage( KSpreadSheet *sheet, KoDocument *document, QString &str )
 
185
{
 
186
  QString title;
 
187
  KoDocumentInfo *info = document->documentInfo();
 
188
  KoDocumentInfoAbout *aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
 
189
  if ( aboutPage && !aboutPage->title().isEmpty() )
 
190
    title = aboutPage->title() + " - ";
 
191
 
 
192
  title += sheet->sheetName();
 
193
 
 
194
      // header
 
195
  str = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" ";
 
196
  str += " \"http://www.w3.org/TR/html4/loose.dtd\"> \n";
 
197
  str += "<html>\n";
 
198
  str += "<head>\n";
 
199
  str += "<meta http-equiv=\"Content-Type\" ";
 
200
  str += QString("content=\"text/html; charset=%1\">\n").arg( m_dialog->encoding()->mimeName() );
 
201
  str += "<meta name=\"Generator\" ";
 
202
  str += "content=\"KSpread HTML Export Filter Version = ";
 
203
  str += KOFFICE_VERSION_STRING;
 
204
  str += "\">\n";
 
205
 
 
206
    // Insert stylesheet
 
207
  if( !m_dialog->customStyleURL().isEmpty() )
 
208
  {
 
209
    str += "<link ref=\"stylesheet\" type=\"text/css\" href=\"";
 
210
    str += m_dialog->customStyleURL();
 
211
    str += "\" title=\"Style\" >\n";
 
212
  }
 
213
 
 
214
  str += "<title>" + title + "</title>\n";
 
215
  str += "</head>\n";
 
216
  str += QString("<body bgcolor=\"#FFFFFF\" dir=\"%1\">\n").arg(
 
217
      sheet->isRightToLeft()?"rtl":"ltr");
 
218
 
 
219
  str += "<a name=\"__top\">\n";
 
220
}
 
221
 
 
222
void HTMLExport::closePage( QString &str )
 
223
{
 
224
  str += "<p align=\"" + html_center + "\"><a href=\"#__top\">" + i18n("Top") + "</a></p>\n";
 
225
  str += "</body>\n";
 
226
  str += "</html>\n\n";
 
227
}
 
228
 
 
229
void HTMLExport::convertSheet( KSpreadSheet *sheet, QString &str, int iMaxUsedRow, int iMaxUsedColumn )
 
230
{
 
231
  QString emptyLines;
 
232
 
 
233
        // Either we get hold of KSpreadTable::m_dctCells and apply the old method below (for sorting)
149
234
      // or, cleaner and already sorted, we use KSpreadTable's API (slower probably, though)
150
 
      int iMaxColumn = table->maxColumn();
151
 
      int iMaxRow = table->maxRow();
152
 
 
153
 
      // determine max number of used columns to make rect table
154
 
      int iUsedColumn=0;
155
 
      int iMaxUsedColumn=0;
156
 
      int iMaxUsedRow=0;
157
 
      int currentrow, currentcolumn;
158
 
 
159
 
      for ( currentrow = 1 ; currentrow < iMaxRow ; ++currentrow)
160
 
      {
161
 
        KSpreadCell * cell = 0L;
162
 
        iUsedColumn=0;
163
 
        for ( currentcolumn = 1 ; currentcolumn < iMaxColumn ; currentcolumn++ )
164
 
        {
165
 
            cell = table->cellAt( currentcolumn, currentrow, false );
166
 
            QString text;
167
 
            if ( !cell->isDefault() && !cell->isEmpty() )
168
 
            {
169
 
                iUsedColumn = currentcolumn;
170
 
            }
171
 
        }
172
 
        if (cell)
173
 
          iUsedColumn += cell->extraXCells();
174
 
        if (iUsedColumn > iMaxUsedColumn)
175
 
          iMaxUsedColumn = iUsedColumn;
176
 
        if ( iUsedColumn > 0 )
177
 
          iMaxUsedRow = currentrow;
178
 
 
179
 
      }
180
 
      iMaxUsedRow++;
181
 
      iMaxUsedColumn++;
 
235
  int iMaxRow = sheet->maxRow();
 
236
 
 
237
  if( !m_dialog->separateFiles() )
 
238
    str += "<a name=\"" + sheet->sheetName().lower().stripWhiteSpace() + "\">\n";
 
239
 
 
240
  str += ("<h1>" + sheet->sheetName() + "</h1><br>\n");
182
241
 
183
242
      // this is just a bad approximation which fails for documents with less than 50 rows, but
184
243
      // we don't need any progress stuff there anyway :) (Werner)
185
 
      int value=0;
186
 
      int step=iMaxRow > 50 ? iMaxRow/50 : 1;
187
 
      int i=1;
188
 
 
189
 
      str += "<" + html_table_tag + html_table_options +
190
 
       QString("dir=\"%1\">\n").arg(table->isRightToLeft()?"rtl":"ltr");
191
 
 
192
 
      unsigned int nonempty_cells_prev=0;
193
 
 
194
 
      for ( currentrow = 1 ; currentrow < iMaxUsedRow ; ++currentrow, ++i )
195
 
      {
196
 
        if(i>step) {
197
 
            value+=2;
198
 
            emit sigProgress(value);
199
 
            i=0;
200
 
        }
201
 
 
202
 
        QString separators;
203
 
        QString line;
204
 
        unsigned int nonempty_cells=0;
205
 
        unsigned int colspan_cells=0;
206
 
 
207
 
        for ( currentcolumn = 1 ; currentcolumn < iMaxUsedColumn ; currentcolumn++ )
208
 
        {
209
 
            KSpreadCell * cell = table->cellAt( currentcolumn, currentrow, false );
210
 
            colspan_cells=cell->extraXCells();
211
 
            if (cell->needsPrinting())
212
 
              nonempty_cells++;
213
 
            QString text;
214
 
            QColor bgcolor = cell->bgColor(currentcolumn,currentrow);
 
244
  int value=0;
 
245
  int step=iMaxRow > 50 ? iMaxRow/50 : 1;
 
246
  int i=1;
 
247
 
 
248
  str += "<" + html_table_tag + html_table_options.arg( m_dialog->useBorders() ? "1" : "0" ).arg( m_dialog->pixelsBetweenCells() ) +
 
249
      QString("dir=\"%1\">\n").arg(sheet->isRightToLeft()?"rtl":"ltr");
 
250
 
 
251
  unsigned int nonempty_cells_prev=0;
 
252
 
 
253
  for ( int currentrow = 1 ; currentrow <= iMaxUsedRow ; ++currentrow, ++i )
 
254
  {
 
255
    if(i>step) {
 
256
      value+=2;
 
257
      emit sigProgress(value);
 
258
      i=0;
 
259
    }
 
260
 
 
261
    QString separators;
 
262
    QString line;
 
263
    unsigned int nonempty_cells=0;
 
264
    unsigned int colspan_cells=0;
 
265
 
 
266
    for ( int currentcolumn = 1 ; currentcolumn <= iMaxUsedColumn ; currentcolumn++ )
 
267
    {
 
268
      KSpreadCell * cell = sheet->cellAt( currentcolumn, currentrow, false );
 
269
      colspan_cells=cell->extraXCells();
 
270
      if (cell->needsPrinting())
 
271
        nonempty_cells++;
 
272
      QString text;
 
273
      QColor bgcolor = cell->bgColor(currentcolumn,currentrow);
215
274
            // FIXME: some formatting seems to be missing with cell->text(), e.g.
216
275
            // "208.00" in KSpread will be "208" in HTML (not always?!)
217
276
 
218
277
 
219
 
            text=cell->strOutText();
 
278
      text=cell->strOutText();
220
279
#if 0
221
280
            switch( cell->content() ) {
222
 
                case KSpreadCell::Text:
 
281
      case KSpreadCell::Text:
223
282
                  text = cell->text();
224
283
                  break;
225
 
                case KSpreadCell::RichText:
226
 
                case KSpreadCell::VisualFormula:
 
284
      case KSpreadCell::RichText:
 
285
      case KSpreadCell::VisualFormula:
227
286
                  text = cell->text(); // untested
228
287
                  break;
229
 
                case KSpreadCell::Formula:
 
288
      case KSpreadCell::Formula:
230
289
                  cell->calc( TRUE ); // Incredible, cells are not calculated if the document was just opened
231
290
                  text = cell->valueString();
232
291
                  break;
233
 
            }
 
292
    }
234
293
            text = cell->prefix(currentrow, currentcolumn) + " " + text + " "
235
294
                 + cell->postfix(currentrow, currentcolumn);
236
295
#endif
237
296
            line += "  <" + html_cell_tag + html_cell_options;
238
 
            if (text.isRightToLeft() != table->isRightToLeft())
239
 
                line += QString(" dir=\"%1\" ").arg(text.isRightToLeft()?"rtl":"ltr");
240
 
            if (bgcolor.isValid() && bgcolor.name()!="#ffffff") // change color only for non-white cells
241
 
              line += " bgcolor=\"" + bgcolor.name() + "\"";
242
 
 
243
 
            switch((KSpreadCell::Align)cell->defineAlignX())
244
 
            {
245
 
            case KSpreadCell::Left:
246
 
                line+=" align=\"" + html_left +"\"";
247
 
                break;
248
 
            case KSpreadCell::Right:
249
 
                line+=" align=\"" + html_right +"\"";
250
 
                break;
251
 
            case KSpreadCell::Center:
252
 
                line+=" align=\"" + html_center +"\"";
253
 
                break;
254
 
            case KSpreadCell::Undefined:
255
 
                break;
256
 
            }
257
 
            switch((KSpreadCell::AlignY)cell-> alignY(currentrow, currentcolumn))
258
 
            {
259
 
            case KSpreadCell::Top:
260
 
                line+=" valign=\"" + html_top +"\"";
261
 
                break;
262
 
            case KSpreadCell::Middle:
263
 
                line+=" valign=\"" + html_middle +"\"";
264
 
                break;
265
 
            case KSpreadCell::Bottom:
266
 
                line+=" valign=\"" + html_bottom +"\"";
267
 
                break;
268
 
            }
269
 
            line+=" width=\""+QString::number(cell->width())+"\"";
270
 
            line+=" height=\""+QString::number(cell->height())+"\"";
271
 
 
272
 
            if (cell->extraXCells()>0)
273
 
            {
274
 
              QString tmp;
275
 
              int extra_cells=cell->extraXCells();
276
 
              line += " colspan=\"" + tmp.setNum(extra_cells+1) + "\"";
277
 
              currentcolumn += extra_cells;
278
 
            }
279
 
            text = text.stripWhiteSpace();
280
 
            if( text.at(0) == '!' ) {
 
297
            if (text.isRightToLeft() != sheet->isRightToLeft())
 
298
        line += QString(" dir=\"%1\" ").arg(text.isRightToLeft()?"rtl":"ltr");
 
299
      if (bgcolor.isValid() && bgcolor.name()!="#ffffff") // change color only for non-white cells
 
300
        line += " bgcolor=\"" + bgcolor.name() + "\"";
 
301
 
 
302
      switch((KSpreadCell::Align)cell->defineAlignX())
 
303
      {
 
304
        case KSpreadCell::Left:
 
305
          line+=" align=\"" + html_left +"\"";
 
306
          break;
 
307
        case KSpreadCell::Right:
 
308
          line+=" align=\"" + html_right +"\"";
 
309
          break;
 
310
        case KSpreadCell::Center:
 
311
          line+=" align=\"" + html_center +"\"";
 
312
          break;
 
313
        case KSpreadCell::Undefined:
 
314
          break;
 
315
      }
 
316
      switch((KSpreadCell::AlignY)cell-> alignY(currentrow, currentcolumn))
 
317
      {
 
318
        case KSpreadCell::Top:
 
319
          line+=" valign=\"" + html_top +"\"";
 
320
          break;
 
321
        case KSpreadCell::Middle:
 
322
          line+=" valign=\"" + html_middle +"\"";
 
323
          break;
 
324
        case KSpreadCell::Bottom:
 
325
          line+=" valign=\"" + html_bottom +"\"";
 
326
          break;
 
327
        case KSpreadCell::UndefinedY:
 
328
          break;
 
329
      }
 
330
      line+=" width=\""+QString::number(cell->width())+"\"";
 
331
      line+=" height=\""+QString::number(cell->height())+"\"";
 
332
 
 
333
      if (cell->extraXCells()>0)
 
334
      {
 
335
        QString tmp;
 
336
        int extra_cells=cell->extraXCells();
 
337
        line += " colspan=\"" + tmp.setNum(extra_cells+1) + "\"";
 
338
        currentcolumn += extra_cells;
 
339
      }
 
340
      text = text.stripWhiteSpace();
 
341
      if( text.at(0) == '!' ) {
281
342
              // this is supposed to be markup, just remove the '!':
282
 
              text = text.right(text.length()-1);
283
 
            } else {
284
 
              // Escape HTML characters. No need to be very efficient IMHO,
285
 
              // so use a RegExp:
286
 
              text.replace (regExpAmp , strAmp)
287
 
                  .replace (regExpLt  , strLt)
288
 
                  .replace (regExpGt  , strGt)
289
 
                  .replace (regExpSpace, nbsp);
290
 
            }
291
 
            line += ">\n";
292
 
 
293
 
            if (cell->textFontBold(currentcolumn,currentrow))
294
 
            {
295
 
              text.insert(0, "<" + html_bold + ">");
296
 
              text.append("</" + html_bold + ">");
297
 
            }
298
 
            if (cell->textFontItalic(currentcolumn,currentrow))
299
 
            {
300
 
              text.insert(0, "<" + html_italic + ">");
301
 
              text.append("</" + html_italic + ">");
302
 
            }
303
 
            if (cell->textFontUnderline(currentcolumn,currentrow))
304
 
            {
305
 
              text.insert(0, "<" + html_underline + ">");
306
 
              text.append("</" + html_underline + ">");
307
 
            }
308
 
            QColor textColor = cell->textColor(currentcolumn,currentrow);
309
 
            if (textColor.isValid() && textColor.name()!="#000000") // change color only for non-default text
310
 
            {
311
 
              text.insert(0, "<font color=\"" + textColor.name() + "\">");
312
 
              text.append("</font>");
313
 
            }
314
 
            line += "  " + text;
315
 
            line += "\n  </" + html_cell_tag + ">\n";
316
 
        }
317
 
 
318
 
        if (nonempty_cells == 0 && nonempty_cells_prev == 0) {
319
 
          nonempty_cells_prev = nonempty_cells;
 
343
        text = text.right(text.length()-1);
 
344
      } else {
 
345
              // Escape HTML characters.
 
346
        text.replace ('&' , strAmp)
 
347
            .replace ('<' , strLt)
 
348
            .replace ('>' , strGt)
 
349
            .replace (' ' , nbsp);
 
350
      }
 
351
      line += ">\n";
 
352
 
 
353
      if (cell->textFontBold(currentcolumn,currentrow))
 
354
      {
 
355
        text.insert(0, "<" + html_bold + ">");
 
356
        text.append("</" + html_bold + ">");
 
357
      }
 
358
      if (cell->textFontItalic(currentcolumn,currentrow))
 
359
      {
 
360
        text.insert(0, "<" + html_italic + ">");
 
361
        text.append("</" + html_italic + ">");
 
362
      }
 
363
      if (cell->textFontUnderline(currentcolumn,currentrow))
 
364
      {
 
365
        text.insert(0, "<" + html_underline + ">");
 
366
        text.append("</" + html_underline + ">");
 
367
      }
 
368
      QColor textColor = cell->textColor(currentcolumn,currentrow);
 
369
      if (textColor.isValid() && textColor.name()!="#000000") // change color only for non-default text
 
370
      {
 
371
        text.insert(0, "<font color=\"" + textColor.name() + "\">");
 
372
        text.append("</font>");
 
373
      }
 
374
      line += "  " + text;
 
375
      line += "\n  </" + html_cell_tag + ">\n";
 
376
    }
 
377
 
 
378
    if (nonempty_cells == 0 && nonempty_cells_prev == 0) {
 
379
      nonempty_cells_prev = nonempty_cells;
320
380
          // skip line if there's more than one empty line
321
 
          continue;
322
 
        } else {
323
 
          nonempty_cells_prev = nonempty_cells;
324
 
          str += emptyLines;
325
 
          str += "<" + html_row_tag + html_row_options + ">\n";
326
 
          str += line;
327
 
          str += "</" + html_row_tag + ">";
328
 
          emptyLines = QString::null;
 
381
      continue;
 
382
    } else {
 
383
      nonempty_cells_prev = nonempty_cells;
 
384
      str += emptyLines;
 
385
      str += "<" + html_row_tag + html_row_options + ">\n";
 
386
      str += line;
 
387
      str += "</" + html_row_tag + ">";
 
388
      emptyLines = QString::null;
329
389
          // Append a CR, but in a temp string -> if no other real line,
330
390
          // then those will be dropped
331
 
          emptyLines += "\n";
332
 
        }
 
391
      emptyLines += "\n";
 
392
    }
 
393
  }
 
394
  str += "\n</" + html_table_tag + ">\n<br>\n";
 
395
}
 
396
 
 
397
void HTMLExport::createSheetSeparator( QString &str )
 
398
{
 
399
  str += ("<p align=\"" + html_center + "\"><a href=\"#__top\">" + i18n("Top") + "</a></p>\n" );
 
400
  str += "<hr width=\"80%\">\n";
 
401
}
 
402
 
 
403
void HTMLExport::writeTOC( const QStringList &sheets, const QString &base, QString &str )
 
404
{
 
405
  // don't create TOC for 1 sheet
 
406
  if( sheets.count() == 1 )
 
407
    return;
 
408
 
 
409
  str += "<p align=\"" + html_center + "\">\n";
 
410
 
 
411
  for( uint i = 0 ; i < sheets.count() ; ++i )
 
412
  {
 
413
    str += "<a href=\"";
 
414
 
 
415
    if( m_dialog->separateFiles() )
 
416
    {
 
417
      str += fileName( base, sheets[i], sheets.count() > 1  );
 
418
    }
 
419
    else
 
420
    {
 
421
      str += "#" + sheets[i].lower().stripWhiteSpace();
 
422
    }
 
423
 
 
424
    str += "\">" + sheets[i] + "</a>\n";
 
425
    if( i != sheets.count() -1 )
 
426
      str += " - ";
 
427
  }
 
428
 
 
429
  str += "</p><hr width=\"80%\">\n";
 
430
}
 
431
 
 
432
QString HTMLExport::fileName( const QString &base, const QString &sheetName, bool multipleFiles )
 
433
{
 
434
     QString fileName = base;
 
435
     if( m_dialog->separateFiles() && multipleFiles )
 
436
     {
 
437
         fileName += "-" + sheetName;
 
438
     }
 
439
     fileName += ".html";
 
440
 
 
441
     return fileName;
 
442
}
 
443
 
 
444
void HTMLExport::detectFilledCells( KSpreadSheet *sheet, int &rows, int &columns )
 
445
{
 
446
  int iMaxColumn = sheet->maxColumn();
 
447
  int iMaxRow = sheet->maxRow();
 
448
  rows = 0;
 
449
  columns = 0;
 
450
 
 
451
  for ( int currentrow = 1 ; currentrow <= iMaxRow ; ++currentrow)
 
452
  {
 
453
    KSpreadCell * cell = 0L;
 
454
    int iUsedColumn=0;
 
455
    for ( int currentcolumn = 1 ; currentcolumn <= iMaxColumn ; currentcolumn++ )
 
456
    {
 
457
      cell = sheet->cellAt( currentcolumn, currentrow, false );
 
458
      QString text;
 
459
      if ( !cell->isDefault() && !cell->isEmpty() )
 
460
      {
 
461
        iUsedColumn = currentcolumn;
333
462
      }
334
 
      str += "\n</" + html_table_tag + ">\n<br>\n";
335
 
 
336
 
    table = ksdoc->map()->nextTable();
337
 
    }
338
 
 
339
 
    str += "</body>\n";
340
 
    str += "</html>\n";
341
 
    str += "\n"; // Last CR
342
 
    emit sigProgress(100);
343
 
 
344
 
    // Ok, now write to export file
345
 
    QFile out(file);
346
 
    if(!out.open(IO_WriteOnly)) {
347
 
        kdError(30501) << "Unable to open output file!" << endl;
348
 
        out.close();
349
 
        return KoFilter::FileNotFound;
350
 
    }
351
 
    QTextStream streamOut(&out);
352
 
    streamOut.setEncoding( QTextStream::UnicodeUTF8 ); // TODO: possibility of choosing other encodings
353
 
    streamOut << str << endl;
354
 
    out.close();
355
 
 
356
 
    return KoFilter::OK;
 
463
    }
 
464
    if (cell)
 
465
      iUsedColumn += cell->extraXCells();
 
466
    if (iUsedColumn > columns)
 
467
      columns = iUsedColumn;
 
468
    if ( iUsedColumn > 0 )
 
469
      rows = currentrow;
 
470
  }
357
471
}
358
472
 
359
473
#include <htmlexport.moc>