Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "sc.hrc"
30 : :
31 : : #include <i18npool/mslangid.hxx>
32 : : #include <sot/formats.hxx>
33 : : #include <sfx2/mieclip.hxx>
34 : : #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
35 : :
36 : : #include "global.hxx"
37 : : #include "scerrors.hxx"
38 : : #include "docsh.hxx"
39 : : #include "undoblk.hxx"
40 : : #include "rangenam.hxx"
41 : : #include "viewdata.hxx"
42 : : #include "tabvwsh.hxx"
43 : : #include "filter.hxx"
44 : : #include "asciiopt.hxx"
45 : : #include "cell.hxx"
46 : : #include "column.hxx"
47 : : #include "docoptio.hxx"
48 : : #include "progress.hxx"
49 : : #include "scitems.hxx"
50 : : #include "editable.hxx"
51 : : #include "compiler.hxx"
52 : : #include "warnbox.hxx"
53 : : #include "clipparam.hxx"
54 : : #include "impex.hxx"
55 : : #include "editutil.hxx"
56 : : #include "patattr.hxx"
57 : : #include "docpool.hxx"
58 : : #include "stringutil.hxx"
59 : :
60 : : #include "globstr.hrc"
61 : : #include <vcl/svapp.hxx>
62 : :
63 : : //========================================================================
64 : :
65 : : // We don't want to end up with 2GB read in one line just because of malformed
66 : : // multiline fields, so chop it _somewhere_, which is twice supported columns
67 : : // times maximum cell content length, 2*1024*64K=128M, and because it's
68 : : // sal_Unicode that's 256MB. If it's 2GB of data without LF we're out of luck
69 : : // anyway.
70 : : static const sal_Int32 nArbitraryLineLengthLimit = 2 * MAXCOLCOUNT * STRING_MAXLEN;
71 : :
72 : : namespace
73 : : {
74 : : const char SYLK_LF[] = "\x1b :";
75 : : const char DOUBLE_SEMICOLON[] = ";;";
76 : : const char DOUBLE_DOUBLEQUOTE[] = "\"\"";
77 : : }
78 : :
79 : : enum SylkVersion
80 : : {
81 : : SYLK_SCALC3, // Wrote wrongly quoted strings and unescaped semicolons.
82 : : SYLK_OOO32, // Correct strings, plus multiline content.
83 : : SYLK_OWN, // Place our new versions, if any, before this value.
84 : : SYLK_OTHER // Assume that aliens wrote correct strings.
85 : : };
86 : :
87 : :
88 : : // Gesamtdokument ohne Undo
89 : :
90 : :
91 : 18 : ScImportExport::ScImportExport( ScDocument* p )
92 : 36 : : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
93 : : nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
94 : : bFormulas( false ), bIncludeFiltered( true ),
95 : : bAll( true ), bSingle( true ), bUndo( false ),
96 : : bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
97 [ + - ]: 36 : mbApi( true ), mExportTextOptions()
[ + - + - ]
98 : : {
99 : 18 : pUndoDoc = NULL;
100 : 18 : pExtOptions = NULL;
101 : 18 : }
102 : :
103 : : // Insert am Punkt ohne Bereichschecks
104 : :
105 : :
106 : 0 : ScImportExport::ScImportExport( ScDocument* p, const ScAddress& rPt )
107 : 0 : : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
108 : : aRange( rPt ),
109 : : nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
110 : : bFormulas( false ), bIncludeFiltered( true ),
111 : : bAll( false ), bSingle( true ), bUndo( pDocSh != NULL ),
112 : : bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
113 [ # # ]: 0 : mbApi( true ), mExportTextOptions()
[ # # # # ]
114 : : {
115 : 0 : pUndoDoc = NULL;
116 : 0 : pExtOptions = NULL;
117 : 0 : }
118 : :
119 : :
120 : : // ctor with a range is only used for export
121 : : //! ctor with a string (and bSingle=true) is also used for DdeSetData
122 : :
123 : 5 : ScImportExport::ScImportExport( ScDocument* p, const ScRange& r )
124 : 10 : : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
125 : : aRange( r ),
126 : : nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
127 : : bFormulas( false ), bIncludeFiltered( true ),
128 : : bAll( false ), bSingle( false ), bUndo( pDocSh != NULL ),
129 : : bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
130 [ + - ]: 10 : mbApi( true ), mExportTextOptions()
[ + - + - ]
131 : : {
132 : 5 : pUndoDoc = NULL;
133 : 5 : pExtOptions = NULL;
134 : : // Zur Zeit nur in einer Tabelle!
135 : 5 : aRange.aEnd.SetTab( aRange.aStart.Tab() );
136 : 5 : }
137 : :
138 : : // String auswerten: Entweder Bereich, Punkt oder Gesamtdoc (bei Fehler)
139 : : // Falls eine View existiert, wird die TabNo der View entnommen!
140 : :
141 : :
142 : 0 : ScImportExport::ScImportExport( ScDocument* p, const String& rPos )
143 : 0 : : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ),
144 : : nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ),
145 : : bFormulas( false ), bIncludeFiltered( true ),
146 : : bAll( false ), bSingle( true ), bUndo( pDocSh != NULL ),
147 : : bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
148 [ # # ]: 0 : mbApi( true ), mExportTextOptions()
[ # # # # ]
149 : : {
150 : 0 : pUndoDoc = NULL;
151 : 0 : pExtOptions = NULL;
152 : :
153 [ # # ]: 0 : SCTAB nTab = ScDocShell::GetCurTab();
154 : 0 : aRange.aStart.SetTab( nTab );
155 [ # # ]: 0 : String aPos( rPos );
156 : : // Benannter Bereich?
157 [ # # ]: 0 : ScRangeName* pRange = pDoc->GetRangeName();
158 [ # # ]: 0 : if( pRange )
159 : : {
160 [ # # ][ # # ]: 0 : const ScRangeData* pData = pRange->findByUpperName(ScGlobal::pCharClass->uppercase(aPos));
[ # # ]
161 [ # # ]: 0 : if (pData)
162 : : {
163 [ # # # # : 0 : if( pData->HasType( RT_REFAREA )
# # ][ # # ]
164 : 0 : || pData->HasType( RT_ABSAREA )
165 : 0 : || pData->HasType( RT_ABSPOS ) )
166 [ # # ]: 0 : pData->GetSymbol( aPos ); // mit dem Inhalt weitertesten
167 : : }
168 : : }
169 [ # # ]: 0 : formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
170 : : // Bereich?
171 [ # # ][ # # ]: 0 : if( aRange.Parse( aPos, pDoc, eConv ) & SCA_VALID )
172 : 0 : bSingle = false;
173 : : // Zelle?
174 [ # # ][ # # ]: 0 : else if( aRange.aStart.Parse( aPos, pDoc, eConv ) & SCA_VALID )
175 : 0 : aRange.aEnd = aRange.aStart;
176 : : else
177 [ # # ]: 0 : bAll = true;
178 : 0 : }
179 : :
180 : :
181 [ + - ]: 23 : ScImportExport::~ScImportExport()
182 : : {
183 [ - + ][ # # ]: 23 : delete pUndoDoc;
184 [ + + ][ + - ]: 23 : delete pExtOptions;
185 : 23 : }
186 : :
187 : :
188 : 6 : void ScImportExport::SetExtOptions( const ScAsciiOptions& rOpt )
189 : : {
190 [ - + ]: 6 : if ( pExtOptions )
191 : 0 : *pExtOptions = rOpt;
192 : : else
193 [ + - ]: 6 : pExtOptions = new ScAsciiOptions( rOpt );
194 : :
195 : : // "normale" Optionen uebernehmen
196 : :
197 : 6 : cSep = rOpt.GetFieldSeps().GetChar(0);
198 : 6 : cStr = rOpt.GetTextSep();
199 : 6 : }
200 : :
201 : :
202 : 0 : bool ScImportExport::IsFormatSupported( sal_uLong nFormat )
203 : : {
204 : : return nFormat == FORMAT_STRING
205 : : || nFormat == SOT_FORMATSTR_ID_SYLK
206 : : || nFormat == SOT_FORMATSTR_ID_LINK
207 : : || nFormat == SOT_FORMATSTR_ID_HTML
208 : : || nFormat == SOT_FORMATSTR_ID_HTML_SIMPLE
209 [ # # ][ # # ]: 0 : || nFormat == SOT_FORMATSTR_ID_DIF;
[ # # ][ # # ]
[ # # ][ # # ]
210 : : }
211 : :
212 : :
213 : : //////////////////////////////////////////////////////////////////////////////
214 : :
215 : : // Vorbereitung fuer Undo: Undo-Dokument erzeugen
216 : :
217 : :
218 : 18 : bool ScImportExport::StartPaste()
219 : : {
220 [ - + ]: 18 : if ( !bAll )
221 : : {
222 [ # # ]: 0 : ScEditableTester aTester( pDoc, aRange );
223 [ # # ]: 0 : if ( !aTester.IsEditable() )
224 : : {
225 : : InfoBox aInfoBox(Application::GetDefDialogParent(),
226 [ # # ][ # # ]: 0 : ScGlobal::GetRscString( aTester.GetMessageId() ) );
[ # # ][ # # ]
227 [ # # ]: 0 : aInfoBox.Execute();
228 [ # # ]: 0 : return false;
229 [ # # ]: 0 : }
230 : : }
231 [ - + ][ # # ]: 18 : if( bUndo && pDocSh && pDoc->IsUndoEnabled())
[ # # ][ - + ]
232 : : {
233 [ # # ]: 0 : pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
234 : 0 : pUndoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
235 : 0 : pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, false, pUndoDoc );
236 : : }
237 : 18 : return true;
238 : : }
239 : :
240 : : // Nachbereitung Insert: Undo/Redo-Aktionen erzeugen, Invalidate/Repaint
241 : :
242 : :
243 : 18 : void ScImportExport::EndPaste()
244 : : {
245 : : bool bHeight = pDocSh && pDocSh->AdjustRowHeight(
246 [ + - ][ + - ]: 18 : aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab() );
247 : :
248 [ - + ][ # # ]: 18 : if( pUndoDoc && pDoc->IsUndoEnabled() )
[ - + ]
249 : : {
250 [ # # ][ # # ]: 0 : ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO );
251 [ # # ]: 0 : pRedoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
252 [ # # ]: 0 : pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, false, pRedoDoc );
253 [ # # ]: 0 : ScMarkData aDestMark;
254 [ # # ]: 0 : aDestMark.SetMarkArea(aRange);
255 [ # # ]: 0 : pDocSh->GetUndoManager()->AddUndoAction(
256 [ # # ][ # # ]: 0 : new ScUndoPaste(pDocSh, aRange, aDestMark, pUndoDoc, pRedoDoc, IDF_ALL, NULL));
[ # # ][ # # ]
[ # # ][ # # ]
257 : : }
258 : 18 : pUndoDoc = NULL;
259 [ + - ]: 18 : if( pDocSh )
260 : : {
261 [ - + ]: 18 : if (!bHeight)
262 [ # # ]: 0 : pDocSh->PostPaint( aRange, PAINT_GRID ); // AdjustRowHeight paintet evtl. selber
263 : 18 : pDocSh->SetDocumentModified();
264 : : }
265 : 18 : ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
266 [ - + ]: 18 : if ( pViewSh )
267 : 0 : pViewSh->UpdateInputHandler();
268 : :
269 : 18 : }
270 : :
271 : : /////////////////////////////////////////////////////////////////////////////
272 : :
273 : 0 : bool ScImportExport::ImportData( const String& /* rMimeType */,
274 : : const ::com::sun::star::uno::Any & /* rValue */ )
275 : : {
276 : : OSL_ENSURE( !this, "Implementation is missing" );
277 : 0 : return false;
278 : : }
279 : :
280 : 5 : bool ScImportExport::ExportData( const String& rMimeType,
281 : : ::com::sun::star::uno::Any & rValue )
282 : : {
283 [ + - ]: 5 : SvMemoryStream aStrm;
284 : : // mba: no BaseURL for data exchange
285 [ + - ][ + - ]: 10 : if( ExportStream( aStrm, String(),
286 [ + - ][ + - ]: 10 : SotExchange::GetFormatIdFromMimeType( rMimeType ) ))
[ + - ]
287 : : {
288 [ + - ]: 5 : aStrm << (sal_uInt8) 0;
289 : : rValue <<= ::com::sun::star::uno::Sequence< sal_Int8 >(
290 [ + - ]: 5 : (sal_Int8*)aStrm.GetData(),
291 [ + - ][ + - ]: 10 : aStrm.Seek( STREAM_SEEK_TO_END ) );
[ + - ][ + - ]
292 : 5 : return true;
293 : : }
294 [ + - ]: 5 : return false;
295 : : }
296 : :
297 : :
298 : 0 : bool ScImportExport::ImportString( const ::rtl::OUString& rText, sal_uLong nFmt )
299 : : {
300 [ # # ]: 0 : switch ( nFmt )
301 : : {
302 : : // formats supporting unicode
303 : : case FORMAT_STRING :
304 : : {
305 [ # # ]: 0 : ScImportStringStream aStrm( rText);
306 [ # # ][ # # ]: 0 : return ImportStream( aStrm, String(), nFmt );
[ # # ][ # # ]
307 : : // ImportStream must handle RTL_TEXTENCODING_UNICODE
308 : : }
309 : : //break;
310 : : default:
311 : : {
312 [ # # ]: 0 : rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
313 [ # # ]: 0 : ::rtl::OString aTmp( rText.getStr(), rText.getLength(), eEnc );
314 [ # # ]: 0 : SvMemoryStream aStrm( (void*)aTmp.getStr(), aTmp.getLength() * sizeof(sal_Char), STREAM_READ );
315 : 0 : aStrm.SetStreamCharSet( eEnc );
316 [ # # ]: 0 : SetNoEndianSwap( aStrm ); //! no swapping in memory
317 [ # # ][ # # ]: 0 : return ImportStream( aStrm, String(), nFmt );
[ # # ][ # # ]
318 : : }
319 : : }
320 : : }
321 : :
322 : :
323 : 0 : bool ScImportExport::ExportString( ::rtl::OUString& rText, sal_uLong nFmt )
324 : : {
325 : : OSL_ENSURE( nFmt == FORMAT_STRING, "ScImportExport::ExportString: Unicode not supported for other formats than FORMAT_STRING" );
326 [ # # ]: 0 : if ( nFmt != FORMAT_STRING )
327 : : {
328 [ # # ]: 0 : rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
329 : 0 : rtl::OString aTmp;
330 [ # # ]: 0 : bool bOk = ExportByteString( aTmp, eEnc, nFmt );
331 [ # # ]: 0 : rText = rtl::OStringToOUString( aTmp, eEnc );
332 : 0 : return bOk;
333 : : }
334 : : // nSizeLimit not needed for OUString
335 : :
336 [ # # ]: 0 : SvMemoryStream aStrm;
337 : 0 : aStrm.SetStreamCharSet( RTL_TEXTENCODING_UNICODE );
338 [ # # ]: 0 : SetNoEndianSwap( aStrm ); //! no swapping in memory
339 : : // mba: no BaseURL for data exc
340 [ # # ][ # # ]: 0 : if( ExportStream( aStrm, String(), nFmt ) )
[ # # ][ # # ]
341 : : {
342 [ # # ]: 0 : aStrm << (sal_Unicode) 0;
343 [ # # ]: 0 : aStrm.Seek( STREAM_SEEK_TO_END );
344 : :
345 [ # # ]: 0 : rText = rtl::OUString( (const sal_Unicode*) aStrm.GetData() );
346 : 0 : return true;
347 : : }
348 : 0 : rText = rtl::OUString();
349 [ # # ]: 0 : return false;
350 : :
351 : : // ExportStream must handle RTL_TEXTENCODING_UNICODE
352 : : }
353 : :
354 : :
355 : 0 : bool ScImportExport::ExportByteString( rtl::OString& rText, rtl_TextEncoding eEnc, sal_uLong nFmt )
356 : : {
357 : : OSL_ENSURE( eEnc != RTL_TEXTENCODING_UNICODE, "ScImportExport::ExportByteString: Unicode not supported" );
358 [ # # ]: 0 : if ( eEnc == RTL_TEXTENCODING_UNICODE )
359 [ # # ]: 0 : eEnc = osl_getThreadTextEncoding();
360 : :
361 [ # # ]: 0 : if (!nSizeLimit)
362 : 0 : nSizeLimit = STRING_MAXLEN;
363 : :
364 [ # # ]: 0 : SvMemoryStream aStrm;
365 : 0 : aStrm.SetStreamCharSet( eEnc );
366 [ # # ]: 0 : SetNoEndianSwap( aStrm ); //! no swapping in memory
367 : : // mba: no BaseURL for data exchange
368 [ # # ][ # # ]: 0 : if( ExportStream( aStrm, String(), nFmt ) )
[ # # ][ # # ]
369 : : {
370 [ # # ]: 0 : aStrm << (sal_Char) 0;
371 [ # # ]: 0 : aStrm.Seek( STREAM_SEEK_TO_END );
372 : : // Sicherheits-Check:
373 [ # # ]: 0 : if( aStrm.Tell() <= (sal_uLong) STRING_MAXLEN )
374 : : {
375 [ # # ]: 0 : rText = (const sal_Char*) aStrm.GetData();
376 : 0 : return true;
377 : : }
378 : : }
379 : 0 : rText = rtl::OString();
380 [ # # ]: 0 : return false;
381 : : }
382 : :
383 : :
384 : 18 : bool ScImportExport::ImportStream( SvStream& rStrm, const String& rBaseURL, sal_uLong nFmt )
385 : : {
386 [ + + ]: 18 : if( nFmt == FORMAT_STRING )
387 : : {
388 [ + - ]: 6 : if( ExtText2Doc( rStrm ) ) // pExtOptions auswerten
389 : 6 : return true;
390 : : }
391 [ + - ]: 12 : if( nFmt == SOT_FORMATSTR_ID_SYLK )
392 : : {
393 [ + - ]: 12 : if( Sylk2Doc( rStrm ) )
394 : 12 : return true;
395 : : }
396 [ # # ]: 0 : if( nFmt == SOT_FORMATSTR_ID_DIF )
397 : : {
398 [ # # ]: 0 : if( Dif2Doc( rStrm ) )
399 : 0 : return true;
400 : : }
401 [ # # ]: 0 : if( nFmt == FORMAT_RTF )
402 : : {
403 [ # # ]: 0 : if( RTF2Doc( rStrm, rBaseURL ) )
404 : 0 : return true;
405 : : }
406 [ # # ]: 0 : if( nFmt == SOT_FORMATSTR_ID_LINK )
407 : 0 : return true; // Link-Import?
408 [ # # ]: 0 : if ( nFmt == SOT_FORMATSTR_ID_HTML )
409 : : {
410 [ # # ]: 0 : if( HTML2Doc( rStrm, rBaseURL ) )
411 : 0 : return true;
412 : : }
413 [ # # ]: 0 : if ( nFmt == SOT_FORMATSTR_ID_HTML_SIMPLE )
414 : : {
415 [ # # ]: 0 : MSE40HTMLClipFormatObj aMSE40ClpObj; // needed to skip the header data
416 [ # # ]: 0 : SvStream* pHTML = aMSE40ClpObj.IsValid( rStrm );
417 [ # # ][ # # ]: 0 : if ( pHTML && HTML2Doc( *pHTML, rBaseURL ) )
[ # # ][ # # ]
418 [ # # ][ # # ]: 0 : return true;
419 : : }
420 : :
421 : 18 : return false;
422 : : }
423 : :
424 : :
425 : 5 : bool ScImportExport::ExportStream( SvStream& rStrm, const String& rBaseURL, sal_uLong nFmt )
426 : : {
427 [ + - ]: 5 : if( nFmt == FORMAT_STRING )
428 : : {
429 [ + - ]: 5 : if( Doc2Text( rStrm ) )
430 : 5 : return true;
431 : : }
432 [ # # ]: 0 : if( nFmt == SOT_FORMATSTR_ID_SYLK )
433 : : {
434 [ # # ]: 0 : if( Doc2Sylk( rStrm ) )
435 : 0 : return true;
436 : : }
437 [ # # ]: 0 : if( nFmt == SOT_FORMATSTR_ID_DIF )
438 : : {
439 [ # # ]: 0 : if( Doc2Dif( rStrm ) )
440 : 0 : return true;
441 : : }
442 [ # # ][ # # ]: 0 : if( nFmt == SOT_FORMATSTR_ID_LINK && !bAll )
443 : : {
444 [ # # ]: 0 : String aDocName;
445 [ # # ]: 0 : if ( pDoc->IsClipboard() )
446 [ # # ][ # # ]: 0 : aDocName = ScGlobal::GetClipDocName();
447 : : else
448 : : {
449 : 0 : SfxObjectShell* pShell = pDoc->GetDocumentShell();
450 [ # # ]: 0 : if (pShell)
451 [ # # ][ # # ]: 0 : aDocName = pShell->GetTitle( SFX_TITLE_FULLNAME );
[ # # ]
452 : : }
453 : :
454 : : OSL_ENSURE( aDocName.Len(), "ClipBoard document has no name! :-/" );
455 [ # # ]: 0 : if( aDocName.Len() )
456 : : {
457 : : // Always use Calc A1 syntax for paste link.
458 [ # # ]: 0 : String aRefName;
459 : 0 : sal_uInt16 nFlags = SCA_VALID | SCA_TAB_3D;
460 [ # # ]: 0 : if( bSingle )
461 [ # # ]: 0 : aRange.aStart.Format( aRefName, nFlags, pDoc, formula::FormulaGrammar::CONV_OOO );
462 : : else
463 : : {
464 [ # # ]: 0 : if( aRange.aStart.Tab() != aRange.aEnd.Tab() )
465 : 0 : nFlags |= SCA_TAB2_3D;
466 [ # # ]: 0 : aRange.Format( aRefName, nFlags, pDoc, formula::FormulaGrammar::CONV_OOO );
467 : : }
468 [ # # ]: 0 : String aAppName = Application::GetAppName();
469 : :
470 : : // extra bits are used to tell the client to prefer external
471 : : // reference link.
472 [ # # ]: 0 : ::rtl::OUString aExtraBits(RTL_CONSTASCII_USTRINGPARAM("calc:extref"));
473 : :
474 [ # # ]: 0 : WriteUnicodeOrByteString( rStrm, aAppName, true );
475 [ # # ]: 0 : WriteUnicodeOrByteString( rStrm, aDocName, true );
476 [ # # ]: 0 : WriteUnicodeOrByteString( rStrm, aRefName, true );
477 [ # # ][ # # ]: 0 : WriteUnicodeOrByteString( rStrm, aExtraBits, true );
[ # # ]
478 [ # # ]: 0 : if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
479 [ # # ]: 0 : rStrm << sal_Unicode(0);
480 : : else
481 [ # # ]: 0 : rStrm << sal_Char(0);
482 [ # # ][ # # ]: 0 : return rStrm.GetError() == SVSTREAM_OK;
483 [ # # ][ # # ]: 0 : }
484 : : }
485 [ # # ]: 0 : if( nFmt == SOT_FORMATSTR_ID_HTML )
486 : : {
487 [ # # ]: 0 : if( Doc2HTML( rStrm, rBaseURL ) )
488 : 0 : return true;
489 : : }
490 [ # # ]: 0 : if( nFmt == FORMAT_RTF )
491 : : {
492 [ # # ]: 0 : if( Doc2RTF( rStrm ) )
493 : 0 : return true;
494 : : }
495 : :
496 : 5 : return false;
497 : : }
498 : :
499 : :
500 : 5 : void ScImportExport::WriteUnicodeOrByteString( SvStream& rStrm, const String& rString, bool bZero )
501 : : {
502 : 5 : rtl_TextEncoding eEnc = rStrm.GetStreamCharSet();
503 [ - + ]: 5 : if ( eEnc == RTL_TEXTENCODING_UNICODE )
504 : : {
505 [ # # ]: 0 : if ( !IsEndianSwap( rStrm ) )
506 : 0 : rStrm.Write( rString.GetBuffer(), rString.Len() * sizeof(sal_Unicode) );
507 : : else
508 : : {
509 : 0 : const sal_Unicode* p = rString.GetBuffer();
510 : 0 : const sal_Unicode* const pStop = p + rString.Len();
511 [ # # ]: 0 : while ( p < pStop )
512 : : {
513 : 0 : rStrm << *p;
514 : : }
515 : : }
516 [ # # ]: 0 : if ( bZero )
517 : 0 : rStrm << sal_Unicode(0);
518 : : }
519 : : else
520 : : {
521 [ + - ][ + - ]: 5 : rtl::OString aByteStr(rtl::OUStringToOString(rString, eEnc));
522 [ + - ]: 5 : rStrm << aByteStr.getStr();
523 [ - + ]: 5 : if ( bZero )
524 [ # # ]: 5 : rStrm << sal_Char(0);
525 : : }
526 : 5 : }
527 : :
528 : :
529 : : // This function could be replaced by endlub()
530 : 5 : void ScImportExport::WriteUnicodeOrByteEndl( SvStream& rStrm )
531 : : {
532 [ - + ]: 5 : if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
533 : : { // same as endl() but unicode
534 [ # # # ]: 0 : switch ( rStrm.GetLineDelimiter() )
535 : : {
536 : : case LINEEND_CR :
537 : 0 : rStrm << sal_Unicode(_CR);
538 : 0 : break;
539 : : case LINEEND_LF :
540 : 0 : rStrm << sal_Unicode(_LF);
541 : 0 : break;
542 : : default:
543 : 0 : rStrm << sal_Unicode(_CR) << sal_Unicode(_LF);
544 : : }
545 : : }
546 : : else
547 : 5 : endl( rStrm );
548 : 5 : }
549 : :
550 : :
551 : : enum QuoteType
552 : : {
553 : : FIELDSTART_QUOTE,
554 : : FIRST_QUOTE,
555 : : SECOND_QUOTE,
556 : : FIELDEND_QUOTE,
557 : : DONTKNOW_QUOTE
558 : : };
559 : :
560 : :
561 : : /** Determine if *p is a quote that ends a quoted field.
562 : :
563 : : Precondition: we are parsing a quoted field already and *p is a quote.
564 : :
565 : : @return
566 : : FIELDEND_QUOTE if end of field quote
567 : : DONTKNOW_QUOTE anything else
568 : : */
569 : 2904 : static QuoteType lcl_isFieldEndQuote( const sal_Unicode* p, const sal_Unicode* pSeps )
570 : : {
571 : : // Due to broken CSV generators that don't double embedded quotes check if
572 : : // a field separator immediately or with trailing spaces follows the quote,
573 : : // only then end the field, or at end of string.
574 : 2904 : const sal_Unicode cBlank = ' ';
575 [ + + ][ - + ]: 2904 : if (p[1] == cBlank && ScGlobal::UnicodeStrChr( pSeps, cBlank))
[ - + ]
576 : 0 : return FIELDEND_QUOTE;
577 [ + + ]: 3024 : while (p[1] == cBlank)
578 : 120 : ++p;
579 [ + + ][ + + ]: 2904 : if (!p[1] || ScGlobal::UnicodeStrChr( pSeps, p[1]))
[ + + ]
580 : 2316 : return FIELDEND_QUOTE;
581 : 2904 : return DONTKNOW_QUOTE;
582 : : }
583 : :
584 : :
585 : : /** Determine if *p is a quote that is escaped by being doubled or ends a
586 : : quoted field.
587 : :
588 : : Precondition: *p is a quote.
589 : :
590 : : @param nQuotes
591 : : Quote characters encountered so far.
592 : : Odd (after opening quote) means either no embedded quotes or only quote
593 : : pairs so far.
594 : : Even means either not in a quoted field or already one quote
595 : : encountered, the first of a pair.
596 : :
597 : : @return
598 : : FIELDSTART_QUOTE if first quote in a field, either starting content or
599 : : embedded so caller should check beforehand.
600 : : FIRST_QUOTE if first of a doubled quote
601 : : SECOND_QUOTE if second of a doubled quote
602 : : FIELDEND_QUOTE if end of field quote
603 : : DONTKNOW_QUOTE if an unescaped quote we don't consider as end of field,
604 : : do not increment nQuotes in caller then!
605 : : */
606 : 1740 : static QuoteType lcl_isEscapedOrFieldEndQuote( sal_Int32 nQuotes, const sal_Unicode* p,
607 : : const sal_Unicode* pSeps, sal_Unicode cStr )
608 : : {
609 [ + + ]: 1740 : if ((nQuotes % 2) == 0)
610 : : {
611 [ + - ]: 144 : if (p[-1] == cStr)
612 : 144 : return SECOND_QUOTE;
613 : : else
614 : : {
615 : : SAL_WARN( "sc", "lcl_isEscapedOrFieldEndQuote: really want a FIELDSTART_QUOTE?");
616 : 0 : return FIELDSTART_QUOTE;
617 : : }
618 : : }
619 [ + + ]: 1596 : if (p[1] == cStr)
620 : 144 : return FIRST_QUOTE;
621 : 1740 : return lcl_isFieldEndQuote( p, pSeps);
622 : : }
623 : :
624 : :
625 : : /** Append characters of [p1,p2) to rField.
626 : :
627 : : @returns TRUE if ok; FALSE if data overflow, truncated
628 : : */
629 : 2334 : static bool lcl_appendLineData( String& rField, const sal_Unicode* p1, const sal_Unicode* p2 )
630 : : {
631 : : OSL_ENSURE( rField.Len() + (p2 - p1) <= STRING_MAXLEN, "lcl_appendLineData: data overflow");
632 [ + - ]: 2334 : if (rField.Len() + (p2 - p1) <= STRING_MAXLEN)
633 : : {
634 : 2334 : rField.Append( p1, sal::static_int_cast<xub_StrLen>( p2 - p1 ) );
635 : 2334 : return true;
636 : : }
637 : : else
638 : : {
639 : : // If STRING_MAXLEN is passed as length, then String attempts to
640 : : // determine the length of the string and comes up with an overflow
641 : : // casted to xub_StrLen again ... so pass max-1, data will be truncated
642 : : // anyway.
643 [ # # ]: 0 : rField.Append( p1, (rField.Len() ? STRING_MAXLEN - rField.Len() : STRING_MAXLEN - 1) );
644 : 2334 : return false;
645 : : }
646 : : }
647 : :
648 : :
649 : : enum DoubledQuoteMode
650 : : {
651 : : DQM_KEEP, // both are taken
652 : : DQM_ESCAPE, // escaped quote, one is taken, one ignored
653 : : DQM_CONCAT, // first is end, next is start, both ignored => strings combined
654 : : DQM_SEPARATE // end one string and begin next
655 : : };
656 : :
657 : 1158 : static const sal_Unicode* lcl_ScanString( const sal_Unicode* p, String& rString,
658 : : const sal_Unicode* pSeps, sal_Unicode cStr, DoubledQuoteMode eMode, bool& rbOverflowCell )
659 : : {
660 : 1158 : p++; //! jump over opening quote
661 : : bool bCont;
662 [ + + ]: 1302 : do
663 : : {
664 : 1302 : bCont = false;
665 : 1302 : const sal_Unicode* p0 = p;
666 : 11292 : for( ;; )
667 : : {
668 [ - + ]: 12594 : if( !*p )
669 : 0 : break;
670 [ + + ]: 12594 : if( *p == cStr )
671 : : {
672 [ + + ]: 1596 : if ( *++p != cStr )
673 : : {
674 : : // break or continue for loop
675 [ + - ]: 1452 : if (eMode == DQM_ESCAPE)
676 : : {
677 [ + + ]: 1452 : if (lcl_isFieldEndQuote( p-1, pSeps) == FIELDEND_QUOTE)
678 : 1158 : break;
679 : : else
680 : 294 : continue;
681 : : }
682 : : else
683 : 0 : break;
684 : : }
685 : : // doubled quote char
686 [ - + - - : 144 : switch ( eMode )
- ]
687 : : {
688 : : case DQM_KEEP :
689 : 0 : p++; // both for us (not breaking for-loop)
690 : 0 : break;
691 : : case DQM_ESCAPE :
692 : 144 : p++; // one for us (breaking for-loop)
693 : 144 : bCont = true; // and more
694 : 144 : break;
695 : : case DQM_CONCAT :
696 [ # # ]: 0 : if ( p0+1 < p )
697 : : {
698 : : // first part
699 [ # # ]: 0 : if (!lcl_appendLineData( rString, p0, p-1))
700 : 0 : rbOverflowCell = true;
701 : : }
702 : 0 : p0 = ++p; // text of next part starts here
703 : 0 : break;
704 : : case DQM_SEPARATE :
705 : : // positioned on next opening quote
706 : 0 : break;
707 : : }
708 [ - + ][ # # ]: 144 : if ( eMode == DQM_ESCAPE || eMode == DQM_SEPARATE )
709 : 144 : break;
710 : : }
711 : : else
712 : 10998 : p++;
713 : : }
714 [ + - ]: 1302 : if ( p0 < p )
715 : : {
716 [ + + ][ + - ]: 1302 : if (!lcl_appendLineData( rString, p0, ((*p || *(p-1) == cStr) ? p-1 : p)))
[ - + ]
717 : 0 : rbOverflowCell = true;
718 : : }
719 : : } while ( bCont );
720 : 1158 : return p;
721 : : }
722 : :
723 : 2823 : void lcl_UnescapeSylk( String & rString, SylkVersion eVersion )
724 : : {
725 : : // Older versions didn't escape the semicolon.
726 : : // Older versions quoted the string and doubled embedded quotes, but not
727 : : // the semicolons, which was plain wrong.
728 [ + + ]: 2823 : if (eVersion >= SYLK_OOO32)
729 [ + - ][ + - ]: 1488 : rString.SearchAndReplaceAll( rtl::OUString(DOUBLE_SEMICOLON), rtl::OUString(';') );
[ + - ][ + - ]
[ + - ]
730 : : else
731 [ + - ][ + - ]: 1335 : rString.SearchAndReplaceAll( rtl::OUString(DOUBLE_DOUBLEQUOTE), rtl::OUString('"') );
[ + - ][ + - ]
[ + - ]
732 : :
733 [ + - ][ + - ]: 2823 : rString.SearchAndReplaceAll( rtl::OUString(SYLK_LF), rtl::OUString(_LF) );
[ + - ][ + - ]
[ + - ]
734 : 2823 : }
735 : :
736 : 2823 : static const sal_Unicode* lcl_ScanSylkString( const sal_Unicode* p,
737 : : String& rString, SylkVersion eVersion )
738 : : {
739 : 2823 : const sal_Unicode* pStartQuote = p;
740 : 2823 : const sal_Unicode* pEndQuote = 0;
741 [ + + ]: 47319 : while( *(++p) )
742 : : {
743 [ + + ]: 44496 : if( *p == '"' )
744 : : {
745 : 2823 : pEndQuote = p;
746 [ + + ]: 2823 : if (eVersion >= SYLK_OOO32)
747 : : {
748 [ - + ]: 1488 : if (*(p+1) == ';')
749 : : {
750 [ # # ]: 0 : if (*(p+2) == ';')
751 : : {
752 : 0 : p += 2; // escaped ';'
753 : 0 : pEndQuote = 0;
754 : : }
755 : : else
756 : 0 : break; // end field
757 : : }
758 : : }
759 : : else
760 : : {
761 [ - + ]: 1335 : if (*(p+1) == '"')
762 : : {
763 : 0 : ++p; // escaped '"'
764 : 0 : pEndQuote = 0;
765 : : }
766 [ - + ]: 1335 : else if (*(p+1) == ';')
767 : 0 : break; // end field
768 : : }
769 : : }
770 : : }
771 [ - + ]: 2823 : if (!pEndQuote)
772 : 0 : pEndQuote = p; // Take all data as string.
773 : 2823 : rString.Append( pStartQuote + 1, sal::static_int_cast<xub_StrLen>( pEndQuote - pStartQuote - 1 ) );
774 : 2823 : lcl_UnescapeSylk( rString, eVersion);
775 : 2823 : return p;
776 : : }
777 : :
778 : 0 : static const sal_Unicode* lcl_ScanSylkFormula( const sal_Unicode* p,
779 : : String& rString, SylkVersion eVersion )
780 : : {
781 : 0 : const sal_Unicode* pStart = p;
782 [ # # ]: 0 : if (eVersion >= SYLK_OOO32)
783 : : {
784 [ # # ]: 0 : while (*p)
785 : : {
786 [ # # ]: 0 : if (*p == ';')
787 : : {
788 [ # # ]: 0 : if (*(p+1) == ';')
789 : 0 : ++p; // escaped ';'
790 : : else
791 : 0 : break; // end field
792 : : }
793 : 0 : ++p;
794 : : }
795 : 0 : rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart));
796 : 0 : lcl_UnescapeSylk( rString, eVersion);
797 : : }
798 : : else
799 : : {
800 : : // Nasty. If in old versions the formula contained a semicolon, it was
801 : : // quoted and embedded quotes were doubled, but semicolons were not. If
802 : : // there was no semicolon, it could still contain quotes and doubled
803 : : // embedded quotes if it was something like ="a""b", which was saved as
804 : : // E"a""b" as is and has to be preserved, even if older versions
805 : : // couldn't even load it correctly. However, theoretically another
806 : : // field might follow and thus the line contain a semicolon again, such
807 : : // as ...;E"a""b";...
808 : 0 : bool bQuoted = false;
809 [ # # ]: 0 : if (*p == '"')
810 : : {
811 : : // May be a quoted expression or just a string constant expression
812 : : // with quotes.
813 [ # # ]: 0 : while (*(++p))
814 : : {
815 [ # # ]: 0 : if (*p == '"')
816 : : {
817 [ # # ]: 0 : if (*(p+1) == '"')
818 : 0 : ++p; // escaped '"'
819 : : else
820 : 0 : break; // closing '"', had no ';' yet
821 : : }
822 [ # # ]: 0 : else if (*p == ';')
823 : : {
824 : 0 : bQuoted = true; // ';' within quoted expression
825 : 0 : break;
826 : : }
827 : : }
828 : 0 : p = pStart;
829 : : }
830 [ # # ]: 0 : if (bQuoted)
831 : 0 : p = lcl_ScanSylkString( p, rString, eVersion);
832 : : else
833 : : {
834 [ # # ][ # # ]: 0 : while (*p && *p != ';')
[ # # ]
835 : 0 : ++p;
836 : 0 : rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart));
837 : : }
838 : : }
839 : 0 : return p;
840 : : }
841 : :
842 : 0 : static void lcl_DoubleEscapeChar( String& rString, sal_Unicode cStr )
843 : : {
844 : 0 : xub_StrLen n = 0;
845 [ # # ]: 0 : while( ( n = rString.Search( cStr, n ) ) != STRING_NOTFOUND )
846 : : {
847 : 0 : rString.Insert( cStr, n );
848 : 0 : n += 2;
849 : : }
850 : 0 : }
851 : :
852 : 0 : static void lcl_WriteString( SvStream& rStrm, String& rString, sal_Unicode cQuote, sal_Unicode cEsc )
853 : : {
854 [ # # ]: 0 : if (cEsc)
855 : 0 : lcl_DoubleEscapeChar( rString, cEsc );
856 : :
857 [ # # ]: 0 : if (cQuote)
858 : : {
859 : 0 : rString.Insert( cQuote, 0 );
860 : 0 : rString.Append( cQuote );
861 : : }
862 : :
863 : 0 : ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
864 : 0 : }
865 : :
866 : 5 : inline void lcl_WriteSimpleString( SvStream& rStrm, const String& rString )
867 : : {
868 : 5 : ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
869 : 5 : }
870 : :
871 : : //////////////////////////////////////////////////////////////////////////////
872 : :
873 : :
874 : 0 : bool ScImportExport::Text2Doc( SvStream& rStrm )
875 : : {
876 : 0 : bool bOk = true;
877 : :
878 : : sal_Unicode pSeps[2];
879 : 0 : pSeps[0] = cSep;
880 : 0 : pSeps[1] = 0;
881 : :
882 : 0 : SCCOL nStartCol = aRange.aStart.Col();
883 : 0 : SCROW nStartRow = aRange.aStart.Row();
884 : 0 : SCCOL nEndCol = aRange.aEnd.Col();
885 : 0 : SCROW nEndRow = aRange.aEnd.Row();
886 : 0 : sal_uLong nOldPos = rStrm.Tell();
887 [ # # ]: 0 : rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
888 : 0 : bool bData = !bSingle;
889 [ # # ]: 0 : if( !bSingle)
890 [ # # ]: 0 : bOk = StartPaste();
891 : :
892 [ # # ]: 0 : while( bOk )
893 : : {
894 : 0 : rtl::OUString aLine;
895 [ # # ]: 0 : String aCell;
896 : 0 : SCROW nRow = nStartRow;
897 [ # # ]: 0 : rStrm.Seek( nOldPos );
898 : 0 : for( ;; )
899 : : {
900 [ # # ]: 0 : rStrm.ReadUniOrByteStringLine( aLine, rStrm.GetStreamCharSet(), nArbitraryLineLengthLimit );
901 [ # # ]: 0 : if( rStrm.IsEof() )
902 : 0 : break;
903 : 0 : SCCOL nCol = nStartCol;
904 : 0 : const sal_Unicode* p = aLine.getStr();
905 [ # # ]: 0 : while( *p )
906 : : {
907 [ # # ]: 0 : aCell.Erase();
908 [ # # ]: 0 : if( *p == cStr )
909 : : {
910 [ # # ]: 0 : p = lcl_ScanString( p, aCell, pSeps, cStr, DQM_KEEP, bOverflowCell );
911 [ # # ][ # # ]: 0 : while( *p && *p != cSep )
[ # # ]
912 : 0 : p++;
913 [ # # ]: 0 : if( *p )
914 : 0 : p++;
915 : : }
916 : : else
917 : : {
918 : 0 : const sal_Unicode* q = p;
919 [ # # ][ # # ]: 0 : while( *p && *p != cSep )
[ # # ]
920 : 0 : p++;
921 [ # # ][ # # ]: 0 : if (!lcl_appendLineData( aCell, q, p))
922 : 0 : bOverflowCell = true; // display warning on import
923 [ # # ]: 0 : if( *p )
924 : 0 : p++;
925 : : }
926 [ # # ][ # # ]: 0 : if (ValidCol(nCol) && ValidRow(nRow) )
[ # # ]
927 : : {
928 [ # # ]: 0 : if( bSingle )
929 : : {
930 [ # # ]: 0 : if (nCol>nEndCol) nEndCol = nCol;
931 [ # # ]: 0 : if (nRow>nEndRow) nEndRow = nRow;
932 : : }
933 [ # # ][ # # ]: 0 : if( bData && nCol <= nEndCol && nRow <= nEndRow )
[ # # ]
934 [ # # ][ # # ]: 0 : pDoc->SetString( nCol, nRow, aRange.aStart.Tab(), aCell );
935 : : }
936 : : else // zuviele Spalten/Zeilen
937 : : {
938 [ # # ]: 0 : if (!ValidRow(nRow))
939 : 0 : bOverflowRow = true; // display warning on import
940 [ # # ]: 0 : if (!ValidCol(nCol))
941 : 0 : bOverflowCol = true; // display warning on import
942 : : }
943 : 0 : ++nCol;
944 : : }
945 : 0 : ++nRow;
946 : : }
947 : :
948 [ # # ]: 0 : if( !bData )
949 : : {
950 : 0 : aRange.aEnd.SetCol( nEndCol );
951 : 0 : aRange.aEnd.SetRow( nEndRow );
952 [ # # ]: 0 : bOk = StartPaste();
953 : 0 : bData = true;
954 : : }
955 : : else
956 : : break;
957 [ # # ][ # # ]: 0 : }
[ # # ]
958 : :
959 [ # # ]: 0 : EndPaste();
960 : 0 : return bOk;
961 : : }
962 : :
963 : : //
964 : : // erweiterter Ascii-Import
965 : : //
966 : :
967 : :
968 : 1083 : static bool lcl_PutString(
969 : : ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rStr, sal_uInt8 nColFormat,
970 : : SvNumberFormatter* pFormatter, bool bDetectNumFormat,
971 : : ::utl::TransliterationWrapper& rTransliteration, CalendarWrapper& rCalendar,
972 : : ::utl::TransliterationWrapper* pSecondTransliteration, CalendarWrapper* pSecondCalendar )
973 : : {
974 : 1083 : bool bMultiLine = false;
975 [ + - ][ + + ]: 1083 : if ( nColFormat == SC_COL_SKIP || !rStr.Len() || !ValidCol(nCol) || !ValidRow(nRow) )
[ + - ][ - + ]
[ + + ]
976 : 222 : return bMultiLine;
977 : :
978 [ - + ]: 861 : if ( nColFormat == SC_COL_TEXT )
979 : : {
980 : : double fDummy;
981 : : sal_uInt32 nIndex;
982 [ # # ][ # # ]: 0 : if (pFormatter->IsNumberFormat(rStr, nIndex, fDummy))
983 : : {
984 : : // Set the format of this cell to Text.
985 [ # # ]: 0 : sal_uInt32 nFormat = pFormatter->GetStandardFormat(NUMBERFORMAT_TEXT);
986 [ # # ][ # # ]: 0 : ScPatternAttr aNewAttrs(pDoc->GetPool());
987 : 0 : SfxItemSet& rSet = aNewAttrs.GetItemSet();
988 [ # # ][ # # ]: 0 : rSet.Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat) );
[ # # ]
989 [ # # ][ # # ]: 0 : pDoc->ApplyPattern(nCol, nRow, nTab, aNewAttrs);
990 : :
991 : : }
992 [ # # ][ # # ]: 0 : pDoc->PutCell( nCol, nRow, nTab, ScBaseCell::CreateTextCell( rStr, pDoc ) );
[ # # ]
993 : 0 : return bMultiLine;
994 : : }
995 : :
996 [ - + ]: 861 : if ( nColFormat == SC_COL_ENGLISH )
997 : : {
998 : : //! SetString mit Extra-Flag ???
999 : :
1000 [ # # ]: 0 : SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
1001 [ # # ]: 0 : sal_uInt32 nEnglish = pDocFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
1002 : : double fVal;
1003 [ # # ][ # # ]: 0 : if ( pDocFormatter->IsNumberFormat( rStr, nEnglish, fVal ) )
1004 : : {
1005 : : // Zahlformat wird nicht auf englisch gesetzt
1006 [ # # ]: 0 : pDoc->SetValue( nCol, nRow, nTab, fVal );
1007 : 0 : return bMultiLine;
1008 : : }
1009 : : // sonst weiter mit SetString
1010 : : }
1011 [ - + ]: 861 : else if ( nColFormat != SC_COL_STANDARD ) // Datumsformate
1012 : : {
1013 : 0 : const sal_uInt16 nMaxNumberParts = 7; // Y-M-D h:m:s.t
1014 : 0 : xub_StrLen nLen = rStr.Len();
1015 : : xub_StrLen nStart[nMaxNumberParts];
1016 : : xub_StrLen nEnd[nMaxNumberParts];
1017 : :
1018 : : sal_uInt16 nDP, nMP, nYP;
1019 [ # # # ]: 0 : switch ( nColFormat )
1020 : : {
1021 : 0 : case SC_COL_YMD: nDP = 2; nMP = 1; nYP = 0; break;
1022 : 0 : case SC_COL_MDY: nDP = 1; nMP = 0; nYP = 2; break;
1023 : : case SC_COL_DMY:
1024 : 0 : default: nDP = 0; nMP = 1; nYP = 2; break;
1025 : : }
1026 : :
1027 : 0 : sal_uInt16 nFound = 0;
1028 : 0 : bool bInNum = false;
1029 [ # # ][ # # ]: 0 : for ( xub_StrLen nPos=0; nPos<nLen && (bInNum ||
[ # # ][ # # ]
1030 : : nFound<nMaxNumberParts); nPos++ )
1031 : : {
1032 [ # # ][ # # ]: 0 : if (bInNum && nFound == 3 && nColFormat == SC_COL_YMD &&
[ # # ]
[ # # # # ]
[ # # ]
1033 : 0 : nPos <= nStart[nFound]+2 && rStr.GetChar(nPos) == 'T')
1034 : 0 : bInNum = false; // ISO-8601: YYYY-MM-DDThh:mm...
1035 [ # # ][ # # ]: 0 : else if ((((!bInNum && nFound==nMP) || (bInNum && nFound==nMP+1))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1036 [ # # ]: 0 : && ScGlobal::pCharClass->isLetterNumeric( rStr, nPos))
1037 [ # # ]: 0 : || ScGlobal::pCharClass->isDigit( rStr, nPos))
1038 : : {
1039 [ # # ]: 0 : if (!bInNum)
1040 : : {
1041 : 0 : bInNum = true;
1042 : 0 : nStart[nFound] = nPos;
1043 : 0 : ++nFound;
1044 : : }
1045 : 0 : nEnd[nFound-1] = nPos;
1046 : : }
1047 : : else
1048 : 0 : bInNum = false;
1049 : : }
1050 : :
1051 [ # # ]: 0 : if ( nFound == 1 )
1052 : : {
1053 : : // try to break one number (without separators) into date fields
1054 : :
1055 : 0 : xub_StrLen nDateStart = nStart[0];
1056 : 0 : xub_StrLen nDateLen = nEnd[0] + 1 - nDateStart;
1057 : :
1058 [ # # ][ # # ]: 0 : if ( nDateLen >= 5 && nDateLen <= 8 &&
[ # # ][ # # ]
1059 [ # # ][ # # ]: 0 : ScGlobal::pCharClass->isNumeric( rStr.Copy( nDateStart, nDateLen ) ) )
[ # # ][ # # ]
[ # # ]
1060 : : {
1061 : : // 6 digits: 2 each for day, month, year
1062 : : // 8 digits: 4 for year, 2 each for day and month
1063 : : // 5 or 7 digits: first field is shortened by 1
1064 : :
1065 : 0 : bool bLongYear = ( nDateLen >= 7 );
1066 [ # # ][ # # ]: 0 : bool bShortFirst = ( nDateLen == 5 || nDateLen == 7 );
1067 : :
1068 : 0 : sal_uInt16 nFieldStart = nDateStart;
1069 [ # # ]: 0 : for (sal_uInt16 nPos=0; nPos<3; nPos++)
1070 : : {
1071 : 0 : sal_uInt16 nFieldEnd = nFieldStart + 1; // default: 2 digits
1072 [ # # ][ # # ]: 0 : if ( bLongYear && nPos == nYP )
1073 : 0 : nFieldEnd += 2; // 2 extra digits for long year
1074 [ # # ][ # # ]: 0 : if ( bShortFirst && nPos == 0 )
1075 : 0 : --nFieldEnd; // first field shortened?
1076 : :
1077 : 0 : nStart[nPos] = nFieldStart;
1078 : 0 : nEnd[nPos] = nFieldEnd;
1079 : 0 : nFieldStart = nFieldEnd + 1;
1080 : : }
1081 : 0 : nFound = 3;
1082 : : }
1083 : : }
1084 : :
1085 [ # # ]: 0 : if ( nFound >= 3 )
1086 : : {
1087 : : using namespace ::com::sun::star;
1088 : 0 : bool bSecondCal = false;
1089 [ # # ][ # # ]: 0 : sal_uInt16 nDay = (sal_uInt16) rStr.Copy( nStart[nDP], nEnd[nDP]+1-nStart[nDP] ).ToInt32();
[ # # ]
1090 [ # # ][ # # ]: 0 : sal_uInt16 nYear = (sal_uInt16) rStr.Copy( nStart[nYP], nEnd[nYP]+1-nStart[nYP] ).ToInt32();
[ # # ]
1091 [ # # ]: 0 : String aMStr = rStr.Copy( nStart[nMP], nEnd[nMP]+1-nStart[nMP] );
1092 [ # # ]: 0 : sal_Int16 nMonth = (sal_Int16) aMStr.ToInt32();
1093 [ # # ]: 0 : if (!nMonth)
1094 : : {
1095 [ # # ][ # # ]: 0 : static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) );
[ # # ][ # # ]
1096 [ # # ][ # # ]: 0 : static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) );
[ # # ][ # # ]
1097 [ # # ]: 0 : uno::Sequence< i18n::CalendarItem2 > xMonths;
1098 : : sal_Int32 i, nMonthCount;
1099 : : // first test all month names from local international
1100 [ # # ][ # # ]: 0 : xMonths = rCalendar.getMonths();
[ # # ]
1101 : 0 : nMonthCount = xMonths.getLength();
1102 [ # # ][ # # ]: 0 : for (i=0; i<nMonthCount && !nMonth; i++)
[ # # ]
1103 : : {
1104 [ # # ][ # # ]: 0 : if ( rTransliteration.isEqual( aMStr, xMonths[i].FullName ) ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
[ # # # # ]
1105 [ # # ][ # # ]: 0 : rTransliteration.isEqual( aMStr, xMonths[i].AbbrevName ) )
[ # # ][ # # ]
[ # # ][ # # ]
1106 : 0 : nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1107 [ # # ][ # # ]: 0 : else if ( i == 8 && rTransliteration.isEqual( aSeptCorrect,
[ # # ][ # # ]
1108 [ # # ][ # # ]: 0 : xMonths[i].AbbrevName ) &&
[ # # ][ # # ]
[ # # ][ # # ]
1109 [ # # ]: 0 : rTransliteration.isEqual( aMStr, aSepShortened ) )
1110 : : { // correct English abbreviation is SEPT,
1111 : : // but data mostly contains SEP only
1112 : 0 : nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1113 : : }
1114 : : }
1115 : : // if none found, then test english month names
1116 [ # # ][ # # ]: 0 : if ( !nMonth && pSecondCalendar && pSecondTransliteration )
[ # # ]
1117 : : {
1118 [ # # ][ # # ]: 0 : xMonths = pSecondCalendar->getMonths();
[ # # ]
1119 : 0 : nMonthCount = xMonths.getLength();
1120 [ # # ][ # # ]: 0 : for (i=0; i<nMonthCount && !nMonth; i++)
[ # # ]
1121 : : {
1122 [ # # ][ # # ]: 0 : if ( pSecondTransliteration->isEqual( aMStr, xMonths[i].FullName ) ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
[ # # # # ]
1123 [ # # ][ # # ]: 0 : pSecondTransliteration->isEqual( aMStr, xMonths[i].AbbrevName ) )
[ # # ][ # # ]
[ # # ][ # # ]
1124 : : {
1125 : 0 : nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1126 : 0 : bSecondCal = true;
1127 : : }
1128 [ # # ][ # # ]: 0 : else if ( i == 8 && pSecondTransliteration->isEqual(
[ # # ]
1129 [ # # ]: 0 : aMStr, aSepShortened ) )
1130 : : { // correct English abbreviation is SEPT,
1131 : : // but data mostly contains SEP only
1132 : 0 : nMonth = sal::static_int_cast<sal_Int16>( i+1 );
1133 : 0 : bSecondCal = true;
1134 : : }
1135 : : }
1136 [ # # ]: 0 : }
1137 : : }
1138 : :
1139 [ # # ]: 0 : SvNumberFormatter* pDocFormatter = pDoc->GetFormatTable();
1140 [ # # ]: 0 : if ( nYear < 100 )
1141 [ # # ]: 0 : nYear = pDocFormatter->ExpandTwoDigitYear( nYear );
1142 : :
1143 [ # # ]: 0 : CalendarWrapper* pCalendar = (bSecondCal ? pSecondCalendar : &rCalendar);
1144 [ # # ]: 0 : sal_Int16 nNumMonths = pCalendar->getNumberOfMonthsInYear();
1145 [ # # ][ # # ]: 0 : if ( nDay && nMonth && nDay<=31 && nMonth<=nNumMonths )
[ # # ][ # # ]
1146 : : {
1147 : 0 : --nMonth;
1148 [ # # ]: 0 : pCalendar->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay );
1149 [ # # ]: 0 : pCalendar->setValue( i18n::CalendarFieldIndex::MONTH, nMonth );
1150 [ # # ]: 0 : pCalendar->setValue( i18n::CalendarFieldIndex::YEAR, nYear );
1151 : : sal_Int16 nHour, nMinute, nSecond, nMilli;
1152 : : // #i14974# The imported value should have no fractional value, so set the
1153 : : // time fields to zero (ICU calendar instance defaults to current date/time)
1154 : 0 : nHour = nMinute = nSecond = nMilli = 0;
1155 [ # # ]: 0 : if (nFound > 3)
1156 [ # # ][ # # ]: 0 : nHour = (sal_Int16) rStr.Copy( nStart[3], nEnd[3]+1-nStart[3]).ToInt32();
[ # # ]
1157 [ # # ]: 0 : if (nFound > 4)
1158 [ # # ][ # # ]: 0 : nMinute = (sal_Int16) rStr.Copy( nStart[4], nEnd[4]+1-nStart[4]).ToInt32();
[ # # ]
1159 [ # # ]: 0 : if (nFound > 5)
1160 [ # # ][ # # ]: 0 : nSecond = (sal_Int16) rStr.Copy( nStart[5], nEnd[5]+1-nStart[5]).ToInt32();
[ # # ]
1161 [ # # ]: 0 : if (nFound > 6)
1162 : : {
1163 : 0 : sal_Unicode cDec = '.';
1164 : 0 : rtl::OUString aT( &cDec, 1);
1165 [ # # ][ # # ]: 0 : aT += rStr.Copy( nStart[6], nEnd[6]+1-nStart[6]);
[ # # ]
1166 : : rtl_math_ConversionStatus eStatus;
1167 : 0 : double fV = rtl::math::stringToDouble( aT, cDec, 0, &eStatus, 0);
1168 [ # # ]: 0 : if (eStatus == rtl_math_ConversionStatus_Ok)
1169 : 0 : nMilli = (sal_Int16) (1000.0 * fV + 0.5);
1170 : : }
1171 [ # # ]: 0 : pCalendar->setValue( i18n::CalendarFieldIndex::HOUR, nHour );
1172 [ # # ]: 0 : pCalendar->setValue( i18n::CalendarFieldIndex::MINUTE, nMinute );
1173 [ # # ]: 0 : pCalendar->setValue( i18n::CalendarFieldIndex::SECOND, nSecond );
1174 [ # # ]: 0 : pCalendar->setValue( i18n::CalendarFieldIndex::MILLISECOND, nMilli );
1175 [ # # ][ # # ]: 0 : if ( pCalendar->isValid() )
1176 : : {
1177 [ # # ]: 0 : double fDiff = DateTime(*pDocFormatter->GetNullDate()) -
1178 [ # # ]: 0 : pCalendar->getEpochStart();
1179 : : // #i14974# must use getLocalDateTime to get the same
1180 : : // date values as set above
1181 [ # # ]: 0 : double fDays = pCalendar->getLocalDateTime();
1182 : 0 : fDays -= fDiff;
1183 : :
1184 : : LanguageType eLatin, eCjk, eCtl;
1185 [ # # ]: 0 : pDoc->GetLanguage( eLatin, eCjk, eCtl );
1186 : 0 : LanguageType eDocLang = eLatin; //! which language for date formats?
1187 : :
1188 [ # # ]: 0 : short nType = (nFound > 3 ? NUMBERFORMAT_DATETIME : NUMBERFORMAT_DATE);
1189 [ # # ]: 0 : sal_uLong nFormat = pDocFormatter->GetStandardFormat( nType, eDocLang );
1190 : : // maybe there is a special format including seconds or milliseconds
1191 [ # # ]: 0 : if (nFound > 5)
1192 [ # # ]: 0 : nFormat = pDocFormatter->GetStandardFormat( fDays, nFormat, nType, eDocLang);
1193 : :
1194 [ # # ][ # # ]: 0 : pDoc->PutCell( nCol, nRow, nTab, new ScValueCell(fDays), nFormat, false );
[ # # ]
1195 : :
1196 : 0 : return bMultiLine; // success
1197 : : }
1198 [ # # ][ # # ]: 0 : }
1199 : : }
1200 : : }
1201 : :
1202 : : // Standard or date not determined -> SetString / EditCell
1203 [ + + ]: 861 : if( rStr.Search( _LF ) == STRING_NOTFOUND )
1204 : : {
1205 [ + - ]: 813 : ScSetStringParam aParam;
1206 : 813 : aParam.mpNumFormatter = pFormatter;
1207 : 813 : aParam.mbDetectNumberFormat = bDetectNumFormat;
1208 : 813 : aParam.meSetTextNumFormat = ScSetStringParam::SpecialNumberOnly;
1209 : 813 : aParam.mbHandleApostrophe = false;
1210 [ + - ][ + - ]: 813 : pDoc->SetString( nCol, nRow, nTab, rStr, &aParam );
1211 : : }
1212 : : else
1213 : : {
1214 : 48 : bMultiLine = true;
1215 [ + - ][ + - ]: 48 : pDoc->PutCell( nCol, nRow, nTab, new ScEditCell( rStr, pDoc ) );
[ + - ]
1216 : : }
1217 : 1083 : return bMultiLine;
1218 : : }
1219 : :
1220 : :
1221 : 0 : String lcl_GetFixed( const rtl::OUString& rLine, sal_Int32 nStart, sal_Int32 nNext,
1222 : : bool& rbIsQuoted, bool& rbOverflowCell )
1223 : : {
1224 : 0 : sal_Int32 nLen = rLine.getLength();
1225 [ # # ]: 0 : if (nNext > nLen)
1226 : 0 : nNext = nLen;
1227 [ # # ]: 0 : if ( nNext <= nStart )
1228 : 0 : return EMPTY_STRING;
1229 : :
1230 : 0 : const sal_Unicode* pStr = rLine.getStr();
1231 : :
1232 : 0 : sal_Int32 nSpace = nNext;
1233 [ # # ][ # # ]: 0 : while ( nSpace > nStart && pStr[nSpace-1] == ' ' )
[ # # ]
1234 : 0 : --nSpace;
1235 : :
1236 [ # # ][ # # ]: 0 : rbIsQuoted = (pStr[nStart] == sal_Unicode('"') && pStr[nSpace-1] == sal_Unicode('"'));
1237 [ # # ]: 0 : if (rbIsQuoted)
1238 : : {
1239 : 0 : bool bFits = (nSpace - nStart - 3 <= STRING_MAXLEN);
1240 : : OSL_ENSURE( bFits, "lcl_GetFixed: line doesn't fit into data");
1241 [ # # ]: 0 : if (bFits)
1242 [ # # ]: 0 : return rLine.copy(nStart+1, nSpace-nStart-2);
1243 : : else
1244 : : {
1245 : 0 : rbOverflowCell = true;
1246 [ # # ]: 0 : return rLine.copy(nStart+1, STRING_MAXLEN);
1247 : : }
1248 : : }
1249 : : else
1250 : : {
1251 : 0 : bool bFits = (nSpace - nStart <= STRING_MAXLEN);
1252 : : OSL_ENSURE( bFits, "lcl_GetFixed: line doesn't fit into data");
1253 [ # # ]: 0 : if (bFits)
1254 [ # # ]: 0 : return rLine.copy(nStart, nSpace-nStart);
1255 : : else
1256 : : {
1257 : 0 : rbOverflowCell = true;
1258 [ # # ]: 0 : return rLine.copy(nStart, STRING_MAXLEN);
1259 : : }
1260 : : }
1261 : : }
1262 : :
1263 : 6 : bool ScImportExport::ExtText2Doc( SvStream& rStrm )
1264 : : {
1265 [ - + ]: 6 : if (!pExtOptions)
1266 [ # # ]: 0 : return Text2Doc( rStrm );
1267 : :
1268 : 6 : sal_uLong nOldPos = rStrm.Tell();
1269 [ + - ]: 6 : rStrm.Seek( STREAM_SEEK_TO_END );
1270 : : ::std::auto_ptr<ScProgress> xProgress( new ScProgress( pDocSh,
1271 [ + - ][ + - ]: 6 : ScGlobal::GetRscString( STR_LOAD_DOC ), rStrm.Tell() - nOldPos ));
[ + - ]
1272 [ + - ]: 6 : rStrm.Seek( nOldPos );
1273 [ + - ]: 6 : rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
1274 : :
1275 [ + - ]: 6 : ScColumn::DoubleAllocSwitch aAllocSwitch(true);
1276 : :
1277 : 6 : SCCOL nStartCol = aRange.aStart.Col();
1278 : 6 : SCCOL nEndCol = aRange.aEnd.Col();
1279 : 6 : SCROW nStartRow = aRange.aStart.Row();
1280 : 6 : SCTAB nTab = aRange.aStart.Tab();
1281 : :
1282 : 6 : bool bFixed = pExtOptions->IsFixedLen();
1283 : 6 : const String& rSeps = pExtOptions->GetFieldSeps();
1284 : 6 : const sal_Unicode* pSeps = rSeps.GetBuffer();
1285 : 6 : bool bMerge = pExtOptions->IsMergeSeps();
1286 : 6 : sal_uInt16 nInfoCount = pExtOptions->GetInfoCount();
1287 : 6 : const sal_Int32* pColStart = pExtOptions->GetColStart();
1288 : 6 : const sal_uInt8* pColFormat = pExtOptions->GetColFormat();
1289 : 6 : long nSkipLines = pExtOptions->GetStartRow();
1290 : :
1291 : 6 : LanguageType eDocLang = pExtOptions->GetLanguage();
1292 [ + - ][ + - ]: 6 : SvNumberFormatter aNumFormatter(pDoc->GetServiceManager(), eDocLang);
1293 : 6 : bool bDetectNumFormat = pExtOptions->IsDetectSpecialNumber();
1294 : :
1295 : : // For date recognition
1296 : : ::utl::TransliterationWrapper aTransliteration(
1297 [ + - ][ + - ]: 6 : pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE );
1298 [ + - ]: 6 : aTransliteration.loadModuleIfNeeded( eDocLang );
1299 [ + - ][ + - ]: 6 : CalendarWrapper aCalendar( pDoc->GetServiceManager() );
1300 : : aCalendar.loadDefaultCalendar(
1301 [ + - ][ + - ]: 6 : MsLangId::convertLanguageToLocale( eDocLang ) );
1302 : 6 : ::utl::TransliterationWrapper* pEnglishTransliteration = NULL;
1303 : 6 : CalendarWrapper* pEnglishCalendar = NULL;
1304 [ + - ]: 6 : if ( eDocLang != LANGUAGE_ENGLISH_US )
1305 : : {
1306 : : pEnglishTransliteration = new ::utl::TransliterationWrapper (
1307 [ + - ][ + - ]: 6 : pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE );
[ + - ]
1308 [ + - ]: 6 : aTransliteration.loadModuleIfNeeded( LANGUAGE_ENGLISH_US );
1309 [ + - ][ + - ]: 6 : pEnglishCalendar = new CalendarWrapper ( pDoc->GetServiceManager() );
[ + - ]
1310 : : pEnglishCalendar->loadDefaultCalendar(
1311 [ + - ][ + - ]: 6 : MsLangId::convertLanguageToLocale( LANGUAGE_ENGLISH_US ) );
1312 : : }
1313 : :
1314 : 6 : rtl::OUString aLine;
1315 [ + - ]: 6 : String aCell;
1316 : : sal_uInt16 i;
1317 : 6 : SCROW nRow = nStartRow;
1318 : :
1319 [ - + ]: 6 : while(--nSkipLines>0)
1320 : : {
1321 [ # # ]: 0 : aLine = ReadCsvLine(rStrm, !bFixed, rSeps, cStr); // content is ignored
1322 [ # # ]: 0 : if ( rStrm.IsEof() )
1323 : 0 : break;
1324 : : }
1325 : :
1326 : : // Determine range for Undo.
1327 : : // TODO: we don't need this during import of a file to a new sheet or
1328 : : // document, could set bDetermineRange=false then.
1329 : 6 : bool bDetermineRange = true;
1330 : :
1331 : : // Row heights don't need to be adjusted on the fly if EndPaste() is called
1332 : : // afterwards, which happens only if bDetermineRange. This variable also
1333 : : // survives the toggle of bDetermineRange down at the end of the do{} loop.
1334 : 6 : bool bRangeIsDetermined = bDetermineRange;
1335 : :
1336 [ + - ][ - + ]: 6 : bool bQuotedAsText = pExtOptions && pExtOptions->IsQuotedAsText();
1337 : :
1338 : 6 : sal_uLong nOriginalStreamPos = rStrm.Tell();
1339 : :
1340 [ + + ]: 12 : do
1341 : : {
1342 : 426 : for( ;; )
1343 : : {
1344 [ + - ]: 438 : aLine = ReadCsvLine(rStrm, !bFixed, rSeps, cStr);
1345 [ + - ][ + + ]: 438 : if ( rStrm.IsEof() && aLine.isEmpty() )
[ + + ]
1346 : 12 : break;
1347 : :
1348 : 426 : sal_Int32 nLineLen = aLine.getLength();
1349 : 426 : SCCOL nCol = nStartCol;
1350 : 426 : bool bMultiLine = false;
1351 [ - + ]: 426 : if ( bFixed ) // Feste Satzlaenge
1352 : : {
1353 : : // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1354 : : // overflow if there is really data following to be put behind
1355 : : // the last column, which doesn't happen if info is
1356 : : // SC_COL_SKIP.
1357 [ # # ][ # # ]: 0 : for ( i=0; i<nInfoCount && nCol <= MAXCOL+1; i++ )
[ # # ]
1358 : : {
1359 : 0 : sal_uInt8 nFmt = pColFormat[i];
1360 [ # # ]: 0 : if (nFmt != SC_COL_SKIP) // sonst auch nCol nicht hochzaehlen
1361 : : {
1362 [ # # ]: 0 : if (nCol > MAXCOL)
1363 : 0 : bOverflowCol = true; // display warning on import
1364 [ # # ]: 0 : else if (!bDetermineRange)
1365 : : {
1366 : 0 : sal_Int32 nStart = pColStart[i];
1367 [ # # ]: 0 : sal_Int32 nNext = ( i+1 < nInfoCount ) ? pColStart[i+1] : nLineLen;
1368 : 0 : bool bIsQuoted = false;
1369 [ # # ][ # # ]: 0 : aCell = lcl_GetFixed( aLine, nStart, nNext, bIsQuoted, bOverflowCell );
[ # # ]
1370 [ # # ][ # # ]: 0 : if (bIsQuoted && bQuotedAsText)
1371 : 0 : nFmt = SC_COL_TEXT;
1372 : :
1373 : : bMultiLine |= lcl_PutString(
1374 : : pDoc, nCol, nRow, nTab, aCell, nFmt,
1375 : : &aNumFormatter, bDetectNumFormat, aTransliteration, aCalendar,
1376 [ # # ]: 0 : pEnglishTransliteration, pEnglishCalendar);
1377 : : }
1378 : 0 : ++nCol;
1379 : : }
1380 : : }
1381 : : }
1382 : : else // Nach Trennzeichen suchen
1383 : : {
1384 : 426 : SCCOL nSourceCol = 0;
1385 : 426 : sal_uInt16 nInfoStart = 0;
1386 : 426 : const sal_Unicode* p = aLine.getStr();
1387 : : // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an
1388 : : // overflow if there is really data following to be put behind
1389 : : // the last column, which doesn't happen if info is
1390 : : // SC_COL_SKIP.
1391 [ + + ][ + - ]: 2592 : while (*p && nCol <= MAXCOL+1)
[ + + ]
1392 : : {
1393 : 2166 : bool bIsQuoted = false;
1394 : : p = ScImportExport::ScanNextFieldFromString( p, aCell,
1395 [ + - ]: 2166 : cStr, pSeps, bMerge, bIsQuoted, bOverflowCell );
1396 : :
1397 : 2166 : sal_uInt8 nFmt = SC_COL_STANDARD;
1398 [ - + ]: 2166 : for ( i=nInfoStart; i<nInfoCount; i++ )
1399 : : {
1400 [ # # ]: 0 : if ( pColStart[i] == nSourceCol + 1 ) // pColStart ist 1-basiert
1401 : : {
1402 : 0 : nFmt = pColFormat[i];
1403 : 0 : nInfoStart = i + 1; // ColInfos sind in Reihenfolge
1404 : 0 : break; // for
1405 : : }
1406 : : }
1407 [ + - ]: 2166 : if ( nFmt != SC_COL_SKIP )
1408 : : {
1409 [ - + ]: 2166 : if (nCol > MAXCOL)
1410 : 0 : bOverflowCol = true; // display warning on import
1411 [ + + ]: 2166 : else if (!bDetermineRange)
1412 : : {
1413 [ + + ][ - + ]: 1083 : if (bIsQuoted && bQuotedAsText)
1414 : 0 : nFmt = SC_COL_TEXT;
1415 : :
1416 : : bMultiLine |= lcl_PutString(
1417 : : pDoc, nCol, nRow, nTab, aCell, nFmt,
1418 : : &aNumFormatter, bDetectNumFormat, aTransliteration,
1419 [ + - ]: 1083 : aCalendar, pEnglishTransliteration, pEnglishCalendar);
1420 : : }
1421 : 2166 : ++nCol;
1422 : : }
1423 : :
1424 : 2166 : ++nSourceCol;
1425 : : }
1426 : : }
1427 [ + + ]: 426 : if (nEndCol < nCol)
1428 : 18 : nEndCol = nCol; //! points to the next free or even MAXCOL+2
1429 : :
1430 [ + + ]: 426 : if (!bDetermineRange)
1431 : : {
1432 [ + + ][ - + ]: 213 : if (bMultiLine && !bRangeIsDetermined && pDocSh)
[ # # ]
1433 [ # # ]: 0 : pDocSh->AdjustRowHeight( nRow, nRow, nTab);
1434 [ + - ]: 213 : xProgress->SetStateOnPercent( rStrm.Tell() - nOldPos );
1435 : : }
1436 : 426 : ++nRow;
1437 [ - + ]: 426 : if ( nRow > MAXROW )
1438 : : {
1439 : 0 : bOverflowRow = true; // display warning on import
1440 : 0 : break; // for
1441 : : }
1442 : : }
1443 : : // so far nRow/nEndCol pointed to the next free
1444 [ + - ]: 12 : if (nRow > nStartRow)
1445 : 12 : --nRow;
1446 [ + - ]: 12 : if (nEndCol > nStartCol)
1447 [ + - ]: 12 : nEndCol = ::std::min( static_cast<SCCOL>(nEndCol - 1), MAXCOL);
1448 : :
1449 [ + + ]: 12 : if (bDetermineRange)
1450 : : {
1451 : 6 : aRange.aEnd.SetCol( nEndCol );
1452 : 6 : aRange.aEnd.SetRow( nRow );
1453 : :
1454 [ # # ][ # # ]: 6 : if ( !mbApi && nStartCol != nEndCol &&
[ - + ][ - + ]
1455 [ # # ]: 0 : !pDoc->IsBlockEmpty( nTab, nStartCol + 1, nStartRow, nEndCol, nRow ) )
1456 : : {
1457 [ # # ][ # # ]: 0 : ScReplaceWarnBox aBox( pDocSh->GetActiveDialogParent() );
1458 [ # # ][ # # ]: 0 : if ( aBox.Execute() != RET_YES )
1459 : : {
1460 [ # # ][ # # ]: 0 : delete pEnglishTransliteration;
1461 [ # # ][ # # ]: 0 : delete pEnglishCalendar;
1462 : 0 : return false;
1463 [ # # ][ # # ]: 0 : }
1464 : : }
1465 : :
1466 [ + - ]: 6 : rStrm.Seek( nOriginalStreamPos );
1467 : 6 : nRow = nStartRow;
1468 [ + - ][ - + ]: 6 : if (!StartPaste())
1469 : : {
1470 [ # # ]: 0 : EndPaste();
1471 : 0 : return false;
1472 : : }
1473 : : }
1474 : :
1475 : 12 : bDetermineRange = !bDetermineRange; // toggle
1476 : 12 : } while (!bDetermineRange);
1477 : :
1478 [ + - ]: 6 : pDoc->DoColResize( nTab, nStartCol, nEndCol, 0 );
1479 : :
1480 [ + - ][ + - ]: 6 : delete pEnglishTransliteration;
1481 [ + - ][ + - ]: 6 : delete pEnglishCalendar;
1482 : :
1483 : 6 : xProgress.reset(); // make room for AdjustRowHeight progress
1484 [ + - ]: 6 : if (bRangeIsDetermined)
1485 [ + - ]: 6 : EndPaste();
1486 : :
1487 [ + - ][ + - ]: 6 : return true;
[ + - ][ + - ]
[ + - ][ + - ]
1488 : : }
1489 : :
1490 : :
1491 : 2166 : const sal_Unicode* ScImportExport::ScanNextFieldFromString( const sal_Unicode* p,
1492 : : String& rField, sal_Unicode cStr, const sal_Unicode* pSeps, bool bMergeSeps, bool& rbIsQuoted,
1493 : : bool& rbOverflowCell )
1494 : : {
1495 : 2166 : rbIsQuoted = false;
1496 : 2166 : rField.Erase();
1497 : 2166 : const sal_Unicode cBlank = ' ';
1498 [ + - ]: 2166 : if (!ScGlobal::UnicodeStrChr( pSeps, cBlank))
1499 : : {
1500 : : // Cope with broken generators that put leading blanks before a quoted
1501 : : // field, like "field1", "field2", "..."
1502 : : // NOTE: this is not in conformance with http://tools.ietf.org/html/rfc4180
1503 : 2166 : const sal_Unicode* pb = p;
1504 [ + + ]: 2238 : while (*pb == cBlank)
1505 : 72 : ++pb;
1506 [ + + ]: 2166 : if (*pb == cStr)
1507 : 1158 : p = pb;
1508 : : }
1509 [ + + ]: 2166 : if ( *p == cStr ) // String in quotes
1510 : : {
1511 : 1158 : rbIsQuoted = true;
1512 : : const sal_Unicode* p1;
1513 : 1158 : p1 = p = lcl_ScanString( p, rField, pSeps, cStr, DQM_ESCAPE, rbOverflowCell );
1514 [ + + ][ + + ]: 1182 : while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
[ + + ]
1515 : 24 : p++;
1516 : : // Append remaining unquoted and undelimited data (dirty, dirty) to
1517 : : // this field.
1518 [ + + ]: 1158 : if (p > p1)
1519 : : {
1520 [ - + ]: 24 : if (!lcl_appendLineData( rField, p1, p))
1521 : 0 : rbOverflowCell = true;
1522 : : }
1523 [ + + ]: 1158 : if( *p )
1524 : 1062 : p++;
1525 : : }
1526 : : else // up to delimiter
1527 : : {
1528 : 1008 : const sal_Unicode* p0 = p;
1529 [ + + ][ + + ]: 9222 : while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) )
[ + + ]
1530 : 8214 : p++;
1531 [ - + ]: 1008 : if (!lcl_appendLineData( rField, p0, p))
1532 : 0 : rbOverflowCell = true;
1533 [ + + ]: 1008 : if( *p )
1534 : 756 : p++;
1535 : : }
1536 [ - + ]: 2166 : if ( bMergeSeps ) // skip following delimiters
1537 : : {
1538 [ # # ][ # # ]: 0 : while ( *p && ScGlobal::UnicodeStrChr( pSeps, *p ) )
[ # # ]
1539 : 0 : p++;
1540 : : }
1541 : 2166 : return p;
1542 : : }
1543 : :
1544 : : namespace {
1545 : :
1546 : : /**
1547 : : * Check if a given string has any line break characters or separators.
1548 : : *
1549 : : * @param rStr string to inspect.
1550 : : * @param cSep separator character.
1551 : : */
1552 : 0 : bool hasLineBreaksOrSeps( const String& rStr, sal_Unicode cSep )
1553 : : {
1554 : 0 : const sal_Unicode* p = rStr.GetBuffer();
1555 [ # # ]: 0 : for (xub_StrLen i = 0, n = rStr.Len(); i < n; ++i, ++p)
1556 : : {
1557 : 0 : sal_Unicode c = *p;
1558 [ # # ]: 0 : if (c == cSep)
1559 : : // separator found.
1560 : 0 : return true;
1561 : :
1562 [ # # ]: 0 : switch (c)
1563 : : {
1564 : : case _LF:
1565 : : case _CR:
1566 : : // line break found.
1567 : 0 : return true;
1568 : : default:
1569 : : ;
1570 : : }
1571 : : }
1572 : 0 : return false;
1573 : : }
1574 : :
1575 : : }
1576 : :
1577 : 5 : bool ScImportExport::Doc2Text( SvStream& rStrm )
1578 : : {
1579 : : SCCOL nCol;
1580 : : SCROW nRow;
1581 : 5 : SCCOL nStartCol = aRange.aStart.Col();
1582 : 5 : SCROW nStartRow = aRange.aStart.Row();
1583 : 5 : SCTAB nStartTab = aRange.aStart.Tab();
1584 : 5 : SCCOL nEndCol = aRange.aEnd.Col();
1585 : 5 : SCROW nEndRow = aRange.aEnd.Row();
1586 : 5 : SCTAB nEndTab = aRange.aEnd.Tab();
1587 : :
1588 [ + - ][ + - ]: 5 : if (!pDoc->GetClipParam().isMultiRange() && nStartTab == nEndTab)
[ + - ][ + - ]
[ + - ]
1589 [ + - ]: 5 : pDoc->ShrinkToDataArea( nStartTab, nStartCol, nStartRow, nEndCol, nEndRow );
1590 : :
1591 [ + - ]: 5 : String aCell;
1592 : :
1593 : 5 : bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF);
1594 : :
1595 [ + + ]: 10 : for (nRow = nStartRow; nRow <= nEndRow; nRow++)
1596 : : {
1597 [ - + ][ # # ]: 5 : if (bIncludeFiltered || !pDoc->RowFiltered( nRow, nStartTab ))
[ # # ][ + - ]
1598 : : {
1599 [ + + ]: 10 : for (nCol = nStartCol; nCol <= nEndCol; nCol++)
1600 : : {
1601 : : CellType eType;
1602 [ + - ]: 5 : pDoc->GetCellType( nCol, nRow, nStartTab, eType );
1603 [ - + - - ]: 5 : switch (eType)
1604 : : {
1605 : : case CELLTYPE_FORMULA:
1606 : : {
1607 [ # # ]: 0 : if (bFormulas)
1608 : : {
1609 [ # # ]: 0 : pDoc->GetFormula( nCol, nRow, nStartTab, aCell );
1610 [ # # ][ # # ]: 0 : if( aCell.Search( cSep ) != STRING_NOTFOUND )
1611 [ # # ]: 0 : lcl_WriteString( rStrm, aCell, cStr, cStr );
1612 : : else
1613 [ # # ]: 0 : lcl_WriteSimpleString( rStrm, aCell );
1614 : : }
1615 : : else
1616 : : {
1617 [ # # ]: 0 : pDoc->GetString( nCol, nRow, nStartTab, aCell );
1618 : :
1619 [ # # ]: 0 : bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND );
1620 [ # # ]: 0 : if( bMultiLineText )
1621 : : {
1622 [ # # ]: 0 : if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
1623 [ # # ]: 0 : aCell.SearchAndReplaceAll( _LF, ' ' );
1624 [ # # ][ # # ]: 0 : else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
1625 [ # # ][ # # ]: 0 : aCell = convertLineEnd(aCell, GetSystemLineEnd());
[ # # ]
1626 : : }
1627 : :
1628 [ # # ][ # # ]: 0 : if( mExportTextOptions.mcSeparatorConvertTo && cSep )
1629 [ # # ]: 0 : aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo );
1630 : :
1631 [ # # ][ # # ]: 0 : if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) )
[ # # ][ # # ]
1632 [ # # ]: 0 : lcl_WriteString( rStrm, aCell, cStr, cStr );
1633 : : else
1634 [ # # ]: 0 : lcl_WriteSimpleString( rStrm, aCell );
1635 : : }
1636 : : }
1637 : 0 : break;
1638 : : case CELLTYPE_VALUE:
1639 : : {
1640 [ + - ]: 5 : pDoc->GetString( nCol, nRow, nStartTab, aCell );
1641 [ + - ]: 5 : lcl_WriteSimpleString( rStrm, aCell );
1642 : : }
1643 : 5 : break;
1644 : : case CELLTYPE_NOTE:
1645 : : case CELLTYPE_NONE:
1646 : 0 : break;
1647 : : default:
1648 : : {
1649 [ # # ]: 0 : pDoc->GetString( nCol, nRow, nStartTab, aCell );
1650 : :
1651 [ # # ]: 0 : bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND );
1652 [ # # ]: 0 : if( bMultiLineText )
1653 : : {
1654 [ # # ]: 0 : if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
1655 [ # # ]: 0 : aCell.SearchAndReplaceAll( _LF, ' ' );
1656 [ # # ][ # # ]: 0 : else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
1657 [ # # ][ # # ]: 0 : aCell = convertLineEnd(aCell, GetSystemLineEnd());
[ # # ]
1658 : : }
1659 : :
1660 [ # # ][ # # ]: 0 : if( mExportTextOptions.mcSeparatorConvertTo && cSep )
1661 [ # # ]: 0 : aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo );
1662 : :
1663 [ # # ][ # # ]: 0 : if( mExportTextOptions.mbAddQuotes && hasLineBreaksOrSeps(aCell, cSep) )
[ # # ]
1664 [ # # ]: 0 : lcl_WriteString( rStrm, aCell, cStr, cStr );
1665 : : else
1666 [ # # ]: 0 : lcl_WriteSimpleString( rStrm, aCell );
1667 : : }
1668 : : }
1669 [ - + ]: 5 : if( nCol < nEndCol )
1670 [ # # ][ # # ]: 0 : lcl_WriteSimpleString( rStrm, rtl::OUString(cSep) );
[ # # ]
1671 : : }
1672 [ + - ]: 5 : WriteUnicodeOrByteEndl( rStrm );
1673 [ - + ]: 5 : if( rStrm.GetError() != SVSTREAM_OK )
1674 : 0 : break;
1675 [ - + ][ # # ]: 5 : if( nSizeLimit && rStrm.Tell() > nSizeLimit )
[ - + ]
1676 : 0 : break;
1677 : : }
1678 : : }
1679 : :
1680 [ + - ]: 5 : return rStrm.GetError() == SVSTREAM_OK;
1681 : : }
1682 : :
1683 : :
1684 : 12 : bool ScImportExport::Sylk2Doc( SvStream& rStrm )
1685 : : {
1686 : 12 : bool bOk = true;
1687 : 12 : bool bMyDoc = false;
1688 : 12 : SylkVersion eVersion = SYLK_OTHER;
1689 : :
1690 : : // US-English separators for StringToDouble
1691 : 12 : sal_Unicode cDecSep = '.';
1692 : 12 : sal_Unicode cGrpSep = ',';
1693 : :
1694 : 12 : SCCOL nStartCol = aRange.aStart.Col();
1695 : 12 : SCROW nStartRow = aRange.aStart.Row();
1696 : 12 : SCCOL nEndCol = aRange.aEnd.Col();
1697 : 12 : SCROW nEndRow = aRange.aEnd.Row();
1698 : 12 : sal_uLong nOldPos = rStrm.Tell();
1699 : 12 : bool bData = !bSingle;
1700 [ + - ]: 12 : ::std::vector< sal_uInt32 > aFormats;
1701 : :
1702 [ - + ]: 12 : if( !bSingle)
1703 [ # # ]: 0 : bOk = StartPaste();
1704 : :
1705 [ + - ]: 24 : while( bOk )
1706 : : {
1707 [ + - ]: 24 : String aLine;
1708 [ + - ]: 24 : String aText;
1709 : 24 : rtl::OString aByteLine;
1710 : 24 : SCCOL nCol = nStartCol;
1711 : 24 : SCROW nRow = nStartRow;
1712 : 24 : SCCOL nRefCol = 1;
1713 : 24 : SCROW nRefRow = 1;
1714 [ + - ]: 24 : rStrm.Seek( nOldPos );
1715 : 18156 : for( ;; )
1716 : : {
1717 : : //! allow unicode
1718 [ + - ]: 18180 : rStrm.ReadLine( aByteLine );
1719 [ + - ][ + - ]: 18180 : aLine = rtl::OStringToOUString(aByteLine, rStrm.GetStreamCharSet());
1720 [ + + ]: 18180 : if( rStrm.IsEof() )
1721 : 6 : break;
1722 : 18174 : const sal_Unicode* p = aLine.GetBuffer();
1723 : 18174 : sal_Unicode cTag = *p++;
1724 [ + + ]: 18174 : if( cTag == 'C' ) // Content
1725 : : {
1726 [ - + ]: 13860 : if( *p++ != ';' )
1727 : 0 : return false;
1728 [ + + ]: 48480 : while( *p )
1729 : : {
1730 : 34620 : sal_Unicode ch = *p++;
1731 : 34620 : ch = ScGlobal::ToUpperAlpha( ch );
1732 [ + + - - : 34620 : switch( ch )
+ - + ]
1733 : : {
1734 : : case 'X':
1735 : 13380 : nCol = static_cast<SCCOL>(rtl::OUString(p).toInt32()) + nStartCol - 1;
1736 : 13380 : break;
1737 : : case 'Y':
1738 : 7332 : nRow = rtl::OUString(p).toInt32() + nStartRow - 1;
1739 : 7332 : break;
1740 : : case 'C':
1741 : 0 : nRefCol = static_cast<SCCOL>(rtl::OUString(p).toInt32()) + nStartCol - 1;
1742 : 0 : break;
1743 : : case 'R':
1744 : 0 : nRefRow = rtl::OUString(p).toInt32() + nStartRow - 1;
1745 : 0 : break;
1746 : : case 'K':
1747 : : {
1748 [ - + ][ # # ]: 13860 : if( !bSingle &&
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1749 : : ( nCol < nStartCol || nCol > nEndCol
1750 : : || nRow < nStartRow || nRow > nEndRow
1751 : : || nCol > MAXCOL || nRow > MAXROW ) )
1752 : 0 : break;
1753 [ + + ]: 13860 : if( !bData )
1754 : : {
1755 [ + + ]: 6930 : if( nRow > nEndRow )
1756 : 663 : nEndRow = nRow;
1757 [ + + ]: 6930 : if( nCol > nEndCol )
1758 : 54 : nEndCol = nCol;
1759 : 6930 : break;
1760 : : }
1761 : : bool bText;
1762 [ + + ]: 6930 : if( *p == '"' )
1763 : : {
1764 : 2823 : bText = true;
1765 [ + - ]: 2823 : aText.Erase();
1766 [ + - ]: 2823 : p = lcl_ScanSylkString( p, aText, eVersion);
1767 : : }
1768 : : else
1769 : 4107 : bText = false;
1770 : 6930 : const sal_Unicode* q = p;
1771 [ + + ][ + - ]: 21651 : while( *q && *q != ';' )
[ + + ]
1772 : 14721 : q++;
1773 [ - + ][ # # ]: 6930 : if ( !(*q == ';' && *(q+1) == 'I') )
1774 : : { // don't ignore value
1775 [ + + ]: 6930 : if( bText )
1776 : : {
1777 : 2823 : pDoc->PutCell( nCol, nRow, aRange.aStart.Tab(),
1778 : : ScBaseCell::CreateTextCell( aText, pDoc),
1779 [ + - ]: 5646 : true);
[ + - + - ]
1780 : : }
1781 : : else
1782 : : {
1783 : : double fVal = rtl_math_uStringToDouble( p,
1784 : 4107 : aLine.GetBuffer() + aLine.Len(),
1785 : 4107 : cDecSep, cGrpSep, NULL, NULL );
1786 [ + - ]: 4107 : pDoc->SetValue( nCol, nRow, aRange.aStart.Tab(), fVal );
1787 : : }
1788 : : }
1789 : : }
1790 : 6930 : break;
1791 : : case 'E':
1792 : : case 'M':
1793 : : {
1794 [ # # ]: 0 : if ( ch == 'M' )
1795 : : {
1796 [ # # ]: 0 : if ( nRefCol < nCol )
1797 : 0 : nRefCol = nCol;
1798 [ # # ]: 0 : if ( nRefRow < nRow )
1799 : 0 : nRefRow = nRow;
1800 [ # # ]: 0 : if ( !bData )
1801 : : {
1802 [ # # ]: 0 : if( nRefRow > nEndRow )
1803 : 0 : nEndRow = nRefRow;
1804 [ # # ]: 0 : if( nRefCol > nEndCol )
1805 : 0 : nEndCol = nRefCol;
1806 : : }
1807 : : }
1808 [ # # ][ # # ]: 0 : if( !bMyDoc || !bData )
1809 : : break;
1810 [ # # ]: 0 : aText = '=';
1811 [ # # ]: 0 : p = lcl_ScanSylkFormula( p, aText, eVersion);
1812 : 0 : ScAddress aPos( nCol, nRow, aRange.aStart.Tab() );
1813 : : /* FIXME: do we want GRAM_ODFF_A1 instead? At the
1814 : : * end it probably should be GRAM_ODFF_R1C1, since
1815 : : * R1C1 is what Excel writes in SYLK. */
1816 : 0 : const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_PODF_A1;
1817 [ # # ]: 0 : ScCompiler aComp( pDoc, aPos);
1818 [ # # ]: 0 : aComp.SetGrammar(eGrammar);
1819 [ # # ]: 0 : ScTokenArray* pCode = aComp.CompileString( aText );
1820 [ # # ]: 0 : if ( ch == 'M' )
1821 : : {
1822 [ # # ]: 0 : ScMarkData aMark;
1823 [ # # ]: 0 : aMark.SelectTable( aPos.Tab(), true );
1824 : : pDoc->InsertMatrixFormula( nCol, nRow, nRefCol,
1825 [ # # ][ # # ]: 0 : nRefRow, aMark, EMPTY_STRING, pCode );
[ # # ][ # # ]
1826 : : }
1827 : : else
1828 : : {
1829 : : ScFormulaCell* pFCell = new ScFormulaCell(
1830 [ # # ][ # # ]: 0 : pDoc, aPos, pCode, eGrammar, MM_NONE);
1831 [ # # ][ # # ]: 0 : pDoc->PutCell( aPos, pFCell );
1832 : : }
1833 [ # # ][ # # ]: 0 : delete pCode; // ctor/InsertMatrixFormula did copy TokenArray
[ # # ]
1834 : : }
1835 : 0 : break;
1836 : : }
1837 [ + + ][ + + ]: 140871 : while( *p && *p != ';' )
[ + + ]
1838 : 106251 : p++;
1839 [ + + ]: 34620 : if( *p )
1840 : 20760 : p++;
1841 : : }
1842 : : }
1843 [ + + ]: 4314 : else if( cTag == 'F' ) // Format
1844 : : {
1845 [ - + ]: 588 : if( *p++ != ';' )
1846 : 0 : return false;
1847 : 588 : sal_Int32 nFormat = -1;
1848 [ + + ]: 2238 : while( *p )
1849 : : {
1850 : 1650 : sal_Unicode ch = *p++;
1851 : 1650 : ch = ScGlobal::ToUpperAlpha( ch );
1852 [ + + + + ]: 1650 : switch( ch )
1853 : : {
1854 : : case 'X':
1855 : 480 : nCol = static_cast<SCCOL>(rtl::OUString(p).toInt32()) + nStartCol - 1;
1856 : 480 : break;
1857 : : case 'Y':
1858 : 66 : nRow = rtl::OUString(p).toInt32() + nStartRow - 1;
1859 : 66 : break;
1860 : : case 'P' :
1861 [ + + ]: 498 : if ( bData )
1862 : : {
1863 : : // F;P<n> sets format code of P;P<code> at
1864 : : // current position, or at ;X;Y if specified.
1865 : : // Note that ;X;Y may appear after ;P
1866 : 249 : const sal_Unicode* p0 = p;
1867 [ + - ][ + + ]: 525 : while( *p && *p != ';' )
[ + + ]
1868 : 276 : p++;
1869 : 249 : rtl::OUString aNumber(p0, p - p0);
1870 : 249 : nFormat = aNumber.toInt32();
1871 : : }
1872 : 498 : break;
1873 : : }
1874 [ + + ][ + + ]: 4650 : while( *p && *p != ';' )
[ + + ]
1875 : 3000 : p++;
1876 [ + + ]: 1650 : if( *p )
1877 : 1062 : p++;
1878 : : }
1879 [ + + ]: 588 : if ( !bData )
1880 : : {
1881 [ + + ]: 294 : if( nRow > nEndRow )
1882 : 30 : nEndRow = nRow;
1883 [ + + ]: 294 : if( nCol > nEndCol )
1884 : 3 : nEndCol = nCol;
1885 : : }
1886 [ + + ][ + - ]: 588 : if ( 0 <= nFormat && nFormat < (sal_Int32)aFormats.size() )
[ + + ]
1887 : : {
1888 [ + - ]: 249 : sal_uInt32 nKey = aFormats[nFormat];
1889 : 249 : pDoc->ApplyAttr( nCol, nRow, aRange.aStart.Tab(),
1890 [ + - + - ]: 498 : SfxUInt32Item( ATTR_VALUE_FORMAT, nKey ) );
[ + - ]
1891 : : }
1892 : : }
1893 [ + + ]: 3726 : else if( cTag == 'P' )
1894 : : {
1895 [ + + ][ + + ]: 3660 : if ( bData && *p == ';' && *(p+1) == 'P' )
[ + + ]
1896 : : {
1897 : 1815 : rtl::OUString aCode( p+2 );
1898 : : // unescape doubled semicolons
1899 : 1815 : aCode = aCode.replaceAll(";;", ";");
1900 : : // get rid of Xcl escape characters
1901 : 1815 : aCode = aCode.replaceAll(rtl::OUString(static_cast<sal_Unicode>(0x1b)), rtl::OUString());
1902 : : xub_StrLen nCheckPos;
1903 : : short nType;
1904 : : sal_uInt32 nKey;
1905 : : pDoc->GetFormatTable()->PutandConvertEntry(
1906 : : aCode, nCheckPos, nType, nKey, LANGUAGE_ENGLISH_US,
1907 [ + - ][ + - ]: 1815 : ScGlobal::eLnge );
1908 [ + - ]: 1815 : if ( nCheckPos )
1909 : 1815 : nKey = 0;
1910 [ + - ]: 1815 : aFormats.push_back( nKey );
1911 : : }
1912 : : }
1913 [ + + ][ + - ]: 66 : else if( cTag == 'I' && *p == 'D' )
1914 : : {
1915 [ + - ]: 24 : aLine.Erase( 0, 4 );
1916 [ + - ][ - + ]: 24 : if (aLine.EqualsAscii( "CALCOOO32" ))
1917 : 0 : eVersion = SYLK_OOO32;
1918 [ + - ][ + + ]: 24 : else if (aLine.EqualsAscii( "SCALC3" ))
1919 : 6 : eVersion = SYLK_SCALC3;
1920 : 24 : bMyDoc = (eVersion <= SYLK_OWN);
1921 : : }
1922 [ + + ]: 42 : else if( cTag == 'E' ) // Ende
1923 : 18 : break;
1924 : : }
1925 [ + + ]: 24 : if( !bData )
1926 : : {
1927 : 12 : aRange.aEnd.SetCol( nEndCol );
1928 : 12 : aRange.aEnd.SetRow( nEndRow );
1929 [ + - ]: 12 : bOk = StartPaste();
1930 : 24 : bData = true;
1931 : : }
1932 : : else
1933 : : break;
1934 [ - + + ]: 24 : }
[ + - ]
[ - + + ]
[ + - ]
[ + - + ]
1935 : :
1936 [ + - ]: 12 : EndPaste();
1937 : 12 : return bOk;
1938 : : }
1939 : :
1940 : :
1941 : 0 : bool ScImportExport::Doc2Sylk( SvStream& rStrm )
1942 : : {
1943 : : SCCOL nCol;
1944 : : SCROW nRow;
1945 : 0 : SCCOL nStartCol = aRange.aStart.Col();
1946 : 0 : SCROW nStartRow = aRange.aStart.Row();
1947 : 0 : SCCOL nEndCol = aRange.aEnd.Col();
1948 : 0 : SCROW nEndRow = aRange.aEnd.Row();
1949 [ # # ]: 0 : String aCellStr;
1950 [ # # ]: 0 : String aValStr;
1951 : : lcl_WriteSimpleString( rStrm,
1952 [ # # ][ # # ]: 0 : String( RTL_CONSTASCII_USTRINGPARAM( "ID;PCALCOOO32")));
[ # # ]
1953 [ # # ]: 0 : WriteUnicodeOrByteEndl( rStrm );
1954 : :
1955 [ # # ]: 0 : for (nRow = nStartRow; nRow <= nEndRow; nRow++)
1956 : : {
1957 [ # # ]: 0 : for (nCol = nStartCol; nCol <= nEndCol; nCol++)
1958 : : {
1959 [ # # ]: 0 : String aBufStr;
1960 : : double nVal;
1961 : 0 : bool bForm = false;
1962 : 0 : SCROW r = nRow - nStartRow + 1;
1963 : 0 : SCCOL c = nCol - nStartCol + 1;
1964 : : ScBaseCell* pCell;
1965 [ # # ]: 0 : pDoc->GetCell( nCol, nRow, aRange.aStart.Tab(), pCell );
1966 [ # # ]: 0 : CellType eType = (pCell ? pCell->GetCellType() : CELLTYPE_NONE);
1967 [ # # # # ]: 0 : switch( eType )
1968 : : {
1969 : : case CELLTYPE_FORMULA:
1970 : 0 : bForm = bFormulas;
1971 [ # # ][ # # ]: 0 : if( pDoc->HasValueData( nCol, nRow, aRange.aStart.Tab()) )
1972 : 0 : goto hasvalue;
1973 : : else
1974 : 0 : goto hasstring;
1975 : :
1976 : : case CELLTYPE_VALUE:
1977 : : hasvalue:
1978 [ # # ]: 0 : pDoc->GetValue( nCol, nRow, aRange.aStart.Tab(), nVal );
1979 : :
1980 : : aValStr = ::rtl::math::doubleToUString( nVal,
1981 : : rtl_math_StringFormat_Automatic,
1982 [ # # ]: 0 : rtl_math_DecimalPlaces_Max, '.', true );
1983 : :
1984 [ # # ]: 0 : aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" ));
1985 [ # # ][ # # ]: 0 : aBufStr += String::CreateFromInt32( c );
[ # # ]
1986 [ # # ]: 0 : aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" ));
1987 [ # # ][ # # ]: 0 : aBufStr += String::CreateFromInt32( r );
[ # # ]
1988 [ # # ]: 0 : aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" ));
1989 [ # # ]: 0 : aBufStr += aValStr;
1990 [ # # ]: 0 : lcl_WriteSimpleString( rStrm, aBufStr );
1991 : 0 : goto checkformula;
1992 : :
1993 : : case CELLTYPE_STRING:
1994 : : case CELLTYPE_EDIT:
1995 : : hasstring:
1996 [ # # ]: 0 : pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCellStr );
1997 [ # # ][ # # ]: 0 : aCellStr.SearchAndReplaceAll( rtl::OUString(_LF), rtl::OUString(SYLK_LF) );
[ # # ][ # # ]
[ # # ]
1998 : :
1999 [ # # ]: 0 : aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" ));
2000 [ # # ][ # # ]: 0 : aBufStr += String::CreateFromInt32( c );
[ # # ]
2001 [ # # ]: 0 : aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" ));
2002 [ # # ][ # # ]: 0 : aBufStr += String::CreateFromInt32( r );
[ # # ]
2003 [ # # ]: 0 : aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" ));
2004 [ # # ]: 0 : lcl_WriteSimpleString( rStrm, aBufStr );
2005 [ # # ]: 0 : lcl_WriteString( rStrm, aCellStr, '"', ';' );
2006 : :
2007 : : checkformula:
2008 [ # # ]: 0 : if( bForm )
2009 : : {
2010 : : const ScFormulaCell* pFCell =
2011 [ # # ]: 0 : static_cast<const ScFormulaCell*>(pCell);
2012 [ # # ]: 0 : switch ( pFCell->GetMatrixFlag() )
2013 : : {
2014 : : case MM_REFERENCE :
2015 [ # # ]: 0 : aCellStr.Erase();
2016 : : break;
2017 : : default:
2018 : 0 : rtl::OUString aOUCellStr;
2019 [ # # ]: 0 : pFCell->GetFormula( aOUCellStr,formula::FormulaGrammar::GRAM_PODF_A1);
2020 [ # # ]: 0 : aCellStr = aOUCellStr;
2021 : : /* FIXME: do we want GRAM_ODFF_A1 instead? At
2022 : : * the end it probably should be
2023 : : * GRAM_ODFF_R1C1, since R1C1 is what Excel
2024 : : * writes in SYLK. */
2025 : : }
2026 [ # # # # : 0 : if ( pFCell->GetMatrixFlag() != MM_NONE &&
# # # # ]
[ # # ]
2027 : 0 : aCellStr.Len() > 2 &&
2028 : 0 : aCellStr.GetChar(0) == '{' &&
2029 : 0 : aCellStr.GetChar(aCellStr.Len()-1) == '}' )
2030 : : { // cut off matrix {} characters
2031 [ # # ]: 0 : aCellStr.Erase(aCellStr.Len()-1,1);
2032 [ # # ]: 0 : aCellStr.Erase(0,1);
2033 : : }
2034 [ # # ]: 0 : if ( aCellStr.GetChar(0) == '=' )
2035 [ # # ]: 0 : aCellStr.Erase(0,1);
2036 [ # # ]: 0 : String aPrefix;
2037 [ # # # ]: 0 : switch ( pFCell->GetMatrixFlag() )
2038 : : {
2039 : : case MM_FORMULA :
2040 : : { // diff expression with 'M' M$-extension
2041 : : SCCOL nC;
2042 : : SCROW nR;
2043 [ # # ]: 0 : pFCell->GetMatColsRows( nC, nR );
2044 : 0 : nC += c - 1;
2045 : 0 : nR += r - 1;
2046 [ # # ]: 0 : aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";R" ) );
2047 [ # # ][ # # ]: 0 : aPrefix += String::CreateFromInt32( nR );
[ # # ]
2048 [ # # ]: 0 : aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) );
2049 [ # # ][ # # ]: 0 : aPrefix += String::CreateFromInt32( nC );
[ # # ]
2050 [ # # ]: 0 : aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";M" ) );
2051 : : }
2052 : 0 : break;
2053 : : case MM_REFERENCE :
2054 : : { // diff expression with 'I' M$-extension
2055 : 0 : ScAddress aPos;
2056 [ # # ]: 0 : pFCell->GetMatrixOrigin( aPos );
2057 [ # # ]: 0 : aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";I;R" ) );
2058 [ # # ][ # # ]: 0 : aPrefix += String::CreateFromInt32( aPos.Row() - nStartRow + 1 );
[ # # ]
2059 [ # # ]: 0 : aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) );
2060 [ # # ][ # # ]: 0 : aPrefix += String::CreateFromInt32( aPos.Col() - nStartCol + 1 );
[ # # ]
2061 : : }
2062 : 0 : break;
2063 : : default:
2064 : : // formula Expression
2065 [ # # ]: 0 : aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";E" ) );
2066 : : }
2067 [ # # ]: 0 : lcl_WriteSimpleString( rStrm, aPrefix );
2068 [ # # ]: 0 : if ( aCellStr.Len() )
2069 [ # # ][ # # ]: 0 : lcl_WriteString( rStrm, aCellStr, 0, ';' );
2070 : : }
2071 [ # # ]: 0 : WriteUnicodeOrByteEndl( rStrm );
2072 : 0 : break;
2073 : :
2074 : : default:
2075 : : {
2076 : : // added to avoid warnings
2077 : : }
2078 : : }
2079 [ # # ]: 0 : }
2080 : : }
2081 [ # # ][ # # ]: 0 : lcl_WriteSimpleString( rStrm, rtl::OUString( 'E' ) );
[ # # ]
2082 [ # # ]: 0 : WriteUnicodeOrByteEndl( rStrm );
2083 [ # # ][ # # ]: 0 : return rStrm.GetError() == SVSTREAM_OK;
2084 : : }
2085 : :
2086 : :
2087 : 0 : bool ScImportExport::Doc2HTML( SvStream& rStrm, const String& rBaseURL )
2088 : : {
2089 : : // CharSet is ignored in ScExportHTML, read from Load/Save HTML options
2090 : 0 : ScFormatFilter::Get().ScExportHTML( rStrm, rBaseURL, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW, bAll,
2091 : 0 : aStreamPath, aNonConvertibleChars );
2092 : 0 : return rStrm.GetError() == SVSTREAM_OK;
2093 : : }
2094 : :
2095 : 0 : bool ScImportExport::Doc2RTF( SvStream& rStrm )
2096 : : {
2097 : : // CharSet is ignored in ScExportRTF
2098 : 0 : ScFormatFilter::Get().ScExportRTF( rStrm, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW );
2099 : 0 : return rStrm.GetError() == SVSTREAM_OK;
2100 : : }
2101 : :
2102 : :
2103 : 0 : bool ScImportExport::Doc2Dif( SvStream& rStrm )
2104 : : {
2105 : : // for DIF in the clipboard, IBM_850 is always used
2106 : 0 : ScFormatFilter::Get().ScExportDif( rStrm, pDoc, aRange, RTL_TEXTENCODING_IBM_850 );
2107 : 0 : return true;
2108 : : }
2109 : :
2110 : :
2111 : 0 : bool ScImportExport::Dif2Doc( SvStream& rStrm )
2112 : : {
2113 : 0 : SCTAB nTab = aRange.aStart.Tab();
2114 [ # # ][ # # ]: 0 : ScDocument* pImportDoc = new ScDocument( SCDOCMODE_UNDO );
2115 [ # # ]: 0 : pImportDoc->InitUndo( pDoc, nTab, nTab );
2116 : :
2117 : : // for DIF in the clipboard, IBM_850 is always used
2118 [ # # ][ # # ]: 0 : ScFormatFilter::Get().ScImportDif( rStrm, pImportDoc, aRange.aStart, RTL_TEXTENCODING_IBM_850 );
2119 : :
2120 : : SCCOL nEndCol;
2121 : : SCROW nEndRow;
2122 [ # # ]: 0 : pImportDoc->GetCellArea( nTab, nEndCol, nEndRow );
2123 : : // if there are no cells in the imported content, nEndCol/nEndRow may be before the start
2124 [ # # ]: 0 : if ( nEndCol < aRange.aStart.Col() )
2125 : 0 : nEndCol = aRange.aStart.Col();
2126 [ # # ]: 0 : if ( nEndRow < aRange.aStart.Row() )
2127 : 0 : nEndRow = aRange.aStart.Row();
2128 : 0 : aRange.aEnd = ScAddress( nEndCol, nEndRow, nTab );
2129 : :
2130 [ # # ]: 0 : bool bOk = StartPaste();
2131 [ # # ]: 0 : if (bOk)
2132 : : {
2133 : 0 : sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
2134 [ # # ]: 0 : pDoc->DeleteAreaTab( aRange, nFlags );
2135 [ # # ]: 0 : pImportDoc->CopyToDocument( aRange, nFlags, false, pDoc );
2136 [ # # ]: 0 : EndPaste();
2137 : : }
2138 : :
2139 [ # # ][ # # ]: 0 : delete pImportDoc;
2140 : :
2141 : 0 : return bOk;
2142 : : }
2143 : :
2144 : :
2145 : 0 : bool ScImportExport::RTF2Doc( SvStream& rStrm, const String& rBaseURL )
2146 : : {
2147 : 0 : ScEEAbsImport *pImp = ScFormatFilter::Get().CreateRTFImport( pDoc, aRange );
2148 [ # # ]: 0 : if (!pImp)
2149 : 0 : return false;
2150 : 0 : pImp->Read( rStrm, rBaseURL );
2151 : 0 : aRange = pImp->GetRange();
2152 : :
2153 : 0 : bool bOk = StartPaste();
2154 [ # # ]: 0 : if (bOk)
2155 : : {
2156 : 0 : sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
2157 : 0 : pDoc->DeleteAreaTab( aRange, nFlags );
2158 : 0 : pImp->WriteToDocument();
2159 : 0 : EndPaste();
2160 : : }
2161 [ # # ]: 0 : delete pImp;
2162 : 0 : return bOk;
2163 : : }
2164 : :
2165 : :
2166 : 0 : bool ScImportExport::HTML2Doc( SvStream& rStrm, const String& rBaseURL )
2167 : : {
2168 : 0 : ScEEAbsImport *pImp = ScFormatFilter::Get().CreateHTMLImport( pDoc, rBaseURL, aRange, true);
2169 [ # # ]: 0 : if (!pImp)
2170 : 0 : return false;
2171 : 0 : pImp->Read( rStrm, rBaseURL );
2172 : 0 : aRange = pImp->GetRange();
2173 : :
2174 : 0 : bool bOk = StartPaste();
2175 [ # # ]: 0 : if (bOk)
2176 : : {
2177 : : // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
2178 : : // a Draw Layer but no Draw View -> create Draw Layer and View here
2179 [ # # ]: 0 : if (pDocSh)
2180 : 0 : pDocSh->MakeDrawLayer();
2181 : :
2182 : 0 : sal_uInt16 nFlags = IDF_ALL & ~IDF_STYLES;
2183 : 0 : pDoc->DeleteAreaTab( aRange, nFlags );
2184 : :
2185 [ # # ]: 0 : if (pExtOptions)
2186 : : {
2187 : : // Pick up import options if available.
2188 : 0 : LanguageType eLang = pExtOptions->GetLanguage();
2189 [ # # ][ # # ]: 0 : SvNumberFormatter aNumFormatter(pDoc->GetServiceManager(), eLang);
2190 : 0 : bool bSpecialNumber = pExtOptions->IsDetectSpecialNumber();
2191 [ # # ][ # # ]: 0 : pImp->WriteToDocument(false, 1.0, &aNumFormatter, bSpecialNumber);
2192 : : }
2193 : : else
2194 : : // Regular import, with no options.
2195 : 0 : pImp->WriteToDocument();
2196 : :
2197 : 0 : EndPaste();
2198 : : }
2199 [ # # ]: 0 : delete pImp;
2200 : 0 : return bOk;
2201 : : }
2202 : :
2203 : : #ifndef DISABLE_DYNLOADING
2204 : :
2205 : : #define RETURN_ERROR { return eERR_INTERN; }
2206 : : class ScFormatFilterMissing : public ScFormatFilterPlugin {
2207 : : public:
2208 : 0 : ScFormatFilterMissing()
2209 : 0 : {
2210 : : OSL_FAIL("Missing file filters");
2211 : 0 : }
2212 [ # # ]: 0 : virtual ~ScFormatFilterMissing() {}
2213 : 0 : virtual FltError ScImportLotus123( SfxMedium&, ScDocument*, CharSet ) RETURN_ERROR
2214 : 0 : virtual FltError ScImportQuattroPro( SfxMedium &, ScDocument * ) RETURN_ERROR
2215 : 0 : virtual FltError ScImportExcel( SfxMedium&, ScDocument*, const EXCIMPFORMAT ) RETURN_ERROR
2216 : 0 : virtual FltError ScImportStarCalc10( SvStream&, ScDocument* ) RETURN_ERROR
2217 : 0 : virtual FltError ScImportDif( SvStream&, ScDocument*, const ScAddress&,
2218 : 0 : const CharSet, sal_uInt32 ) RETURN_ERROR
2219 : 0 : virtual FltError ScImportRTF( SvStream&, const String&, ScDocument*, ScRange& ) RETURN_ERROR
2220 : 0 : virtual FltError ScImportHTML( SvStream&, const String&, ScDocument*, ScRange&, double, bool, SvNumberFormatter*, bool ) RETURN_ERROR
2221 : :
2222 : 0 : virtual ScEEAbsImport *CreateRTFImport( ScDocument*, const ScRange& ) { return NULL; }
2223 : 0 : virtual ScEEAbsImport *CreateHTMLImport( ScDocument*, const String&, const ScRange&, bool ) { return NULL; }
2224 : 0 : virtual String GetHTMLRangeNameList( ScDocument*, const String& ) { return String(); }
2225 : :
2226 : 0 : virtual FltError ScExportExcel5( SfxMedium&, ScDocument*, ExportFormatExcel, CharSet ) RETURN_ERROR
2227 : 0 : virtual FltError ScExportDif( SvStream&, ScDocument*, const ScAddress&, const CharSet, sal_uInt32 ) RETURN_ERROR
2228 : 0 : virtual FltError ScExportDif( SvStream&, ScDocument*, const ScRange&, const CharSet, sal_uInt32 ) RETURN_ERROR
2229 : 0 : virtual FltError ScExportHTML( SvStream&, const String&, ScDocument*, const ScRange&, const CharSet, bool,
2230 : 0 : const String&, String& ) RETURN_ERROR
2231 : 0 : virtual FltError ScExportRTF( SvStream&, ScDocument*, const ScRange&, const CharSet ) RETURN_ERROR
2232 : : };
2233 : :
2234 : 0 : extern "C" { static void SAL_CALL thisModule() {} }
2235 : :
2236 : : #else
2237 : :
2238 : : extern "C" {
2239 : : ScFormatFilterPlugin* ScFilterCreate();
2240 : : }
2241 : :
2242 : : #endif
2243 : :
2244 : : typedef ScFormatFilterPlugin * (*FilterFn)(void);
2245 : 70 : ScFormatFilterPlugin &ScFormatFilter::Get()
2246 : : {
2247 : : static ScFormatFilterPlugin *plugin;
2248 : :
2249 [ + + ]: 70 : if (plugin != NULL)
2250 : 62 : return *plugin;
2251 : :
2252 : : #ifndef DISABLE_DYNLOADING
2253 [ + - ]: 8 : ::rtl::OUString sFilterLib(RTL_CONSTASCII_USTRINGPARAM(SVLIBRARY("scfilt")));
2254 [ + - ][ + - ]: 8 : static ::osl::Module aModule;
2255 [ + - ]: 8 : bool bLoaded = aModule.loadRelative(&thisModule, sFilterLib);
2256 [ - + ]: 8 : if (!bLoaded)
2257 [ # # ]: 0 : bLoaded = aModule.load(sFilterLib);
2258 [ + - ]: 8 : if (bLoaded)
2259 : : {
2260 [ + - ][ + - ]: 8 : oslGenericFunction fn = aModule.getFunctionSymbol( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ScFilterCreate" )) );
2261 [ + - ]: 8 : if (fn != NULL)
2262 [ + - ]: 8 : plugin = reinterpret_cast<FilterFn>(fn)();
2263 : : }
2264 [ - + ]: 8 : if (plugin == NULL)
2265 [ # # ]: 0 : plugin = new ScFormatFilterMissing();
2266 : : #else
2267 : : plugin = ScFilterCreate();
2268 : : #endif
2269 : :
2270 : 70 : return *plugin;
2271 : : }
2272 : :
2273 : : // Precondition: pStr is guaranteed to be non-NULL and points to a 0-terminated
2274 : : // array.
2275 : 10266 : inline const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr,
2276 : : sal_Unicode c )
2277 : : {
2278 [ + + ]: 18714 : while (*pStr)
2279 : : {
2280 [ + + ]: 10266 : if (*pStr == c)
2281 : 1818 : return pStr;
2282 : 8448 : ++pStr;
2283 : : }
2284 : 10266 : return 0;
2285 : : }
2286 : :
2287 : 438 : rtl::OUString ReadCsvLine( SvStream &rStream, bool bEmbeddedLineBreak,
2288 : : const String& rFieldSeparators, sal_Unicode cFieldQuote )
2289 : : {
2290 : 438 : rtl::OUString aStr;
2291 [ + - ]: 438 : rStream.ReadUniOrByteStringLine(aStr, rStream.GetStreamCharSet(), nArbitraryLineLengthLimit);
2292 : :
2293 [ + - ]: 438 : if (bEmbeddedLineBreak)
2294 : : {
2295 : 438 : const sal_Unicode* pSeps = rFieldSeparators.GetBuffer();
2296 : :
2297 : : // See if the separator(s) include tab.
2298 : 438 : bool bTabSep = lcl_UnicodeStrChr(pSeps, '\t') != NULL;
2299 : :
2300 : 438 : QuoteType eQuoteState = FIELDEND_QUOTE;
2301 : 438 : bool bFieldStart = true;
2302 : :
2303 : 438 : sal_Int32 nLastOffset = 0;
2304 : 438 : sal_Int32 nQuotes = 0;
2305 [ + + ][ + - ]: 996 : while (!rStream.IsEof() && aStr.getLength() < nArbitraryLineLengthLimit)
[ + + ]
2306 : : {
2307 : : const sal_Unicode *p, *pStart;
2308 : 558 : p = pStart = aStr.getStr();
2309 : 558 : p += nLastOffset;
2310 [ + + ]: 24534 : while (*p)
2311 : : {
2312 [ + + ]: 23976 : if (nQuotes)
2313 : : {
2314 [ - + ][ # # ]: 17172 : if (bTabSep && *p == '\t' && (nQuotes % 2) != 0)
[ # # ]
2315 : : {
2316 : : // When tab-delimited, tab char ends quoted sequence
2317 : : // even if we haven't reached the end quote. Doing
2318 : : // this helps keep mal-formed rows from damaging
2319 : : // other, well-formed rows.
2320 : 0 : nQuotes = 0;
2321 : 0 : break;
2322 : : }
2323 : :
2324 [ + + ]: 17172 : if (*p == cFieldQuote)
2325 : : {
2326 [ + + ]: 2904 : if (bFieldStart)
2327 : : {
2328 : 984 : ++nQuotes;
2329 : 984 : bFieldStart = false;
2330 : 984 : eQuoteState = FIELDSTART_QUOTE;
2331 : : }
2332 : : // Do not detect a FIELDSTART_QUOTE if not in
2333 : : // bFieldStart mode, in which case for unquoted content
2334 : : // we are in FIELDEND_QUOTE state.
2335 [ + + ]: 1920 : else if (eQuoteState != FIELDEND_QUOTE)
2336 : : {
2337 [ + - ]: 1740 : eQuoteState = lcl_isEscapedOrFieldEndQuote( nQuotes, p, pSeps, cFieldQuote);
2338 : : // DONTKNOW_QUOTE is an embedded unescaped quote we
2339 : : // don't count for pairing.
2340 [ + + ]: 1740 : if (eQuoteState != DONTKNOW_QUOTE)
2341 : 1446 : ++nQuotes;
2342 : : }
2343 : : }
2344 [ + + ]: 14268 : else if (eQuoteState == FIELDEND_QUOTE)
2345 : : {
2346 [ + + ]: 3270 : if (bFieldStart)
2347 : : // If blank is a separator it starts a field, if it
2348 : : // is not and thus maybe leading before quote we
2349 : : // are still at start of field regarding quotes.
2350 [ + + ][ + + ]: 702 : bFieldStart = (*p == ' ' || lcl_UnicodeStrChr( pSeps, *p) != NULL);
2351 : : else
2352 : 2568 : bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != NULL);
2353 : : }
2354 : : }
2355 : : else
2356 : : {
2357 [ + + ][ + + ]: 6804 : if (*p == cFieldQuote && bFieldStart)
2358 : : {
2359 : 174 : nQuotes = 1;
2360 : 174 : eQuoteState = FIELDSTART_QUOTE;
2361 : 174 : bFieldStart = false;
2362 : : }
2363 [ + - ]: 6630 : else if (eQuoteState == FIELDEND_QUOTE)
2364 : : {
2365 : : // This also skips leading blanks at beginning of line
2366 : : // if followed by a quote. It's debatable whether we
2367 : : // actually want that or not, but congruent with what
2368 : : // ScanNextFieldFromString() does.
2369 [ + + ]: 6630 : if (bFieldStart)
2370 [ + - ][ - + ]: 378 : bFieldStart = (*p == ' ' || lcl_UnicodeStrChr( pSeps, *p) != NULL);
2371 : : else
2372 : 6252 : bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != NULL);
2373 : : }
2374 : : }
2375 : : // A quote character inside a field content does not start
2376 : : // a quote.
2377 : 23976 : ++p;
2378 : : }
2379 : :
2380 [ + + ]: 558 : if (nQuotes % 2 == 0)
2381 : : // We still have a (theoretical?) problem here if due to
2382 : : // nArbitraryLineLengthLimit we split a string right between a
2383 : : // doubled quote pair.
2384 : 426 : break;
2385 : : else
2386 : : {
2387 : 132 : nLastOffset = aStr.getLength();
2388 : 132 : rtl::OUString aNext;
2389 [ + - ]: 132 : rStream.ReadUniOrByteStringLine(aNext, rStream.GetStreamCharSet(), nArbitraryLineLengthLimit);
2390 : 132 : aStr += rtl::OUString( sal_Unicode(_LF));
2391 : 132 : aStr += aNext;
2392 : : }
2393 : : }
2394 : : }
2395 : 438 : return aStr;
2396 : : }
2397 : :
2398 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|