Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <math.h>
21 :
22 : #include <svl/zforlist.hxx>
23 : #include <osl/diagnose.h>
24 : #include "attrib.hxx"
25 : #include "dif.hxx"
26 : #include "docpool.hxx"
27 : #include "document.hxx"
28 : #include "filter.hxx"
29 : #include "fprogressbar.hxx"
30 : #include "ftools.hxx"
31 : #include "patattr.hxx"
32 : #include "scerrors.hxx"
33 : #include "scitems.hxx"
34 : #include "stringutil.hxx"
35 : #include <boost/scoped_ptr.hpp>
36 :
37 : const sal_Unicode pKeyTABLE[] = { 'T', 'A', 'B', 'L', 'E', 0 };
38 : const sal_Unicode pKeyVECTORS[] = { 'V', 'E', 'C', 'T', 'O', 'R', 'S', 0 };
39 : const sal_Unicode pKeyTUPLES[] = { 'T', 'U', 'P', 'L', 'E', 'S', 0 };
40 : const sal_Unicode pKeyDATA[] = { 'D', 'A', 'T', 'A', 0 };
41 : const sal_Unicode pKeyBOT[] = { 'B', 'O', 'T', 0 };
42 : const sal_Unicode pKeyEOD[] = { 'E', 'O', 'D', 0 };
43 : const sal_Unicode pKeyERROR[] = { 'E', 'R', 'R', 'O', 'R', 0 };
44 : const sal_Unicode pKeyTRUE[] = { 'T', 'R', 'U', 'E', 0 };
45 : const sal_Unicode pKeyFALSE[] = { 'F', 'A', 'L', 'S', 'E', 0 };
46 : const sal_Unicode pKeyNA[] = { 'N', 'A', 0 };
47 : const sal_Unicode pKeyV[] = { 'V', 0 };
48 : const sal_Unicode pKey1_0[] = { '1', ',', '0', 0 };
49 :
50 1 : FltError ScFormatFilterPluginImpl::ScImportDif( SvStream& rIn, ScDocument* pDoc, const ScAddress& rInsPos,
51 : const rtl_TextEncoding eVon, sal_uInt32 nDifOption )
52 : {
53 1 : DifParser aDifParser( rIn, nDifOption, *pDoc, eVon );
54 :
55 1 : const bool bPlain = aDifParser.IsPlain();
56 :
57 1 : SCTAB nBaseTab = rInsPos.Tab();
58 :
59 1 : TOPIC eTopic = T_UNKNOWN;
60 1 : bool bSyntErrWarn = false;
61 1 : bool bOverflowWarn = false;
62 :
63 1 : OUString& aData = aDifParser.aData;
64 :
65 1 : rIn.Seek( 0 );
66 :
67 2 : ScfStreamProgressBar aPrgrsBar( rIn, pDoc->GetDocumentShell() );
68 :
69 6 : while( eTopic != T_DATA && eTopic != T_END )
70 : {
71 4 : eTopic = aDifParser.GetNextTopic();
72 :
73 4 : aPrgrsBar.Progress();
74 :
75 4 : const bool bData = !aData.isEmpty();
76 :
77 4 : switch( eTopic )
78 : {
79 : case T_TABLE:
80 : {
81 1 : if( aDifParser.nVector != 0 || aDifParser.nVal != 1 )
82 0 : bSyntErrWarn = true;
83 1 : if( bData )
84 1 : pDoc->RenameTab( nBaseTab, aData );
85 : }
86 1 : break;
87 : case T_VECTORS:
88 : {
89 1 : if( aDifParser.nVector != 0 )
90 0 : bSyntErrWarn = true;
91 : }
92 1 : break;
93 : case T_TUPLES:
94 : {
95 1 : if( aDifParser.nVector != 0 )
96 0 : bSyntErrWarn = true;
97 : }
98 1 : break;
99 : case T_DATA:
100 : {
101 1 : if( aDifParser.nVector != 0 || aDifParser.nVal != 0 )
102 0 : bSyntErrWarn = true;
103 : }
104 1 : break;
105 : case T_LABEL:
106 : case T_COMMENT:
107 : case T_SIZE:
108 : case T_PERIODICITY:
109 : case T_MAJORSTART:
110 : case T_MINORSTART:
111 : case T_TRUELENGTH:
112 : case T_UINITS:
113 : case T_DISPLAYUNITS:
114 : case T_END:
115 : case T_UNKNOWN:
116 0 : break;
117 : default:
118 : OSL_FAIL( "ScImportDif - missing enum" );
119 : }
120 :
121 : }
122 :
123 1 : if( eTopic == T_DATA )
124 : { // data starts here
125 1 : SCCOL nBaseCol = rInsPos.Col();
126 :
127 1 : SCCOL nColCnt = SCCOL_MAX;
128 1 : SCROW nRowCnt = rInsPos.Row();
129 1 : DifAttrCache aAttrCache( bPlain );
130 :
131 1 : DATASET eAkt = D_UNKNOWN;
132 :
133 1 : ScSetStringParam aStrParam; // used to set string value without number detection.
134 1 : aStrParam.setTextInput();
135 :
136 39 : while( eAkt != D_EOD )
137 : {
138 37 : eAkt = aDifParser.GetNextDataset();
139 :
140 37 : aPrgrsBar.Progress();
141 37 : ScAddress aPos(nColCnt, nRowCnt, nBaseTab);
142 :
143 37 : switch( eAkt )
144 : {
145 : case D_BOT:
146 4 : if( nColCnt < SCCOL_MAX )
147 3 : nRowCnt++;
148 4 : nColCnt = nBaseCol;
149 4 : break;
150 : case D_EOD:
151 1 : break;
152 : case D_NUMERIC: // Number cell
153 6 : if( nColCnt == SCCOL_MAX )
154 0 : nColCnt = nBaseCol;
155 :
156 6 : if( ValidCol(nColCnt) && ValidRow(nRowCnt) )
157 : {
158 6 : pDoc->EnsureTable(nBaseTab);
159 :
160 6 : if( DifParser::IsV( aData.getStr() ) )
161 : {
162 6 : pDoc->SetValue(aPos, aDifParser.fVal);
163 6 : if( !bPlain )
164 : aAttrCache.SetNumFormat( nColCnt, nRowCnt,
165 6 : aDifParser.nNumFormat );
166 : }
167 0 : else if( aData == pKeyTRUE || aData == pKeyFALSE )
168 : {
169 0 : pDoc->SetValue(aPos, aDifParser.fVal);
170 0 : if( bPlain )
171 0 : aAttrCache.SetLogical( nColCnt, nRowCnt );
172 : else
173 : aAttrCache.SetNumFormat( nColCnt, nRowCnt,
174 0 : aDifParser.nNumFormat );
175 : }
176 0 : else if( aData == pKeyNA || aData == pKeyERROR )
177 : {
178 0 : pDoc->SetString(aPos, aData, &aStrParam);
179 : }
180 : else
181 : {
182 0 : OUString aTmp = "#IND:" + aData + "?";
183 0 : pDoc->SetString(aPos, aTmp, &aStrParam);
184 : }
185 : }
186 : else
187 0 : bOverflowWarn = true;
188 :
189 6 : nColCnt++;
190 6 : break;
191 : case D_STRING: // Text cell
192 26 : if( nColCnt == SCCOL_MAX )
193 0 : nColCnt = nBaseCol;
194 :
195 26 : if( ValidCol(nColCnt) && ValidRow(nRowCnt) )
196 : {
197 26 : if (!aData.isEmpty())
198 : {
199 2 : pDoc->EnsureTable(nBaseTab);
200 2 : pDoc->SetTextCell(aPos, aData);
201 : }
202 : }
203 : else
204 0 : bOverflowWarn = true;
205 :
206 26 : nColCnt++;
207 26 : break;
208 : case D_UNKNOWN:
209 0 : break;
210 : case D_SYNT_ERROR:
211 0 : break;
212 : default:
213 : OSL_FAIL( "ScImportDif - missing enum" );
214 : }
215 : }
216 :
217 1 : aAttrCache.Apply( *pDoc, nBaseTab );
218 : }
219 : else
220 0 : return eERR_FORMAT;
221 :
222 1 : if( bSyntErrWarn )
223 :
224 : // FIXME: Add proper Warnung!
225 0 : return eERR_RNGOVRFLW;
226 :
227 1 : else if( bOverflowWarn )
228 0 : return eERR_RNGOVRFLW;
229 : else
230 2 : return eERR_OK;
231 : }
232 :
233 1 : DifParser::DifParser( SvStream& rNewIn, const sal_uInt32 nOption, ScDocument& rDoc, rtl_TextEncoding e )
234 : : fVal(0.0)
235 : , nVector(0)
236 : , nVal(0)
237 : , nNumFormat(0)
238 : , eCharSet(e)
239 1 : , rIn(rNewIn)
240 : {
241 1 : if ( rIn.GetStreamCharSet() != eCharSet )
242 : {
243 : OSL_FAIL( "CharSet passed overrides and modifies StreamCharSet" );
244 1 : rIn.SetStreamCharSet( eCharSet );
245 : }
246 1 : rIn.StartReadingUnicodeText( eCharSet );
247 :
248 1 : bPlain = ( nOption == SC_DIFOPT_PLAIN );
249 :
250 1 : if( bPlain )
251 0 : pNumFormatter = NULL;
252 : else
253 1 : pNumFormatter = rDoc.GetFormatTable();
254 1 : }
255 :
256 4 : TOPIC DifParser::GetNextTopic()
257 : {
258 : enum STATE { S_VectorVal, S_Data, S_END, S_START, S_UNKNOWN, S_ERROR_L2 };
259 :
260 : static const sal_Unicode pKeyLABEL[] = { 'L', 'A', 'B', 'E', 'L', 0 };
261 : static const sal_Unicode pKeyCOMMENT[] = { 'C', 'O', 'M', 'M', 'E', 'N', 'T', 0 };
262 : static const sal_Unicode pKeySIZE[] = { 'S', 'I', 'Z', 'E', 0 };
263 : static const sal_Unicode pKeyPERIODICITY[] = { 'P', 'E', 'R', 'I', 'O', 'D', 'I', 'C', 'I', 'T', 'Y', 0 };
264 : static const sal_Unicode pKeyMAJORSTART[] = { 'M', 'A', 'J', 'O', 'R', 'S', 'T', 'A', 'R', 'T', 0 };
265 : static const sal_Unicode pKeyMINORSTART[] = { 'M', 'I', 'N', 'O', 'R', 'S', 'T', 'A', 'R', 'T', 0 };
266 : static const sal_Unicode pKeyTRUELENGTH[] = { 'T', 'R', 'U', 'E', 'L', 'E', 'N', 'G', 'T', 'H', 0 };
267 : static const sal_Unicode pKeyUINITS[] = { 'U', 'I', 'N', 'I', 'T', 'S', 0 };
268 : static const sal_Unicode pKeyDISPLAYUNITS[] = { 'D', 'I', 'S', 'P', 'L', 'A', 'Y', 'U', 'N', 'I', 'T', 'S', 0 };
269 : static const sal_Unicode pKeyUNKNOWN[] = { 0 };
270 :
271 : static const sal_Unicode* ppKeys[] =
272 : {
273 : pKeyTABLE, // 0
274 : pKeyVECTORS,
275 : pKeyTUPLES,
276 : pKeyDATA,
277 : pKeyLABEL,
278 : pKeyCOMMENT, // 5
279 : pKeySIZE,
280 : pKeyPERIODICITY,
281 : pKeyMAJORSTART,
282 : pKeyMINORSTART,
283 : pKeyTRUELENGTH, // 10
284 : pKeyUINITS,
285 : pKeyDISPLAYUNITS,
286 : pKeyUNKNOWN // 13
287 : };
288 :
289 : static const TOPIC pTopics[] =
290 : {
291 : T_TABLE, // 0
292 : T_VECTORS,
293 : T_TUPLES,
294 : T_DATA,
295 : T_LABEL,
296 : T_COMMENT, // 5
297 : T_SIZE,
298 : T_PERIODICITY,
299 : T_MAJORSTART,
300 : T_MINORSTART,
301 : T_TRUELENGTH, // 10
302 : T_UINITS,
303 : T_DISPLAYUNITS,
304 : T_UNKNOWN // 13
305 : };
306 :
307 4 : STATE eS = S_START;
308 4 : OUString aLine;
309 :
310 4 : nVector = 0;
311 4 : nVal = 0;
312 4 : TOPIC eRet = T_UNKNOWN;
313 :
314 20 : while( eS != S_END )
315 : {
316 12 : if( !ReadNextLine( aLine ) )
317 : {
318 0 : eS = S_END;
319 0 : eRet = T_END;
320 : }
321 :
322 12 : switch( eS )
323 : {
324 : case S_START:
325 : {
326 : const sal_Unicode* pRef;
327 4 : sal_uInt16 nCnt = 0;
328 4 : bool bSearch = true;
329 :
330 4 : pRef = ppKeys[ nCnt ];
331 :
332 18 : while( bSearch )
333 : {
334 10 : if( aLine == pRef )
335 : {
336 4 : eRet = pTopics[ nCnt ];
337 4 : bSearch = false;
338 : }
339 : else
340 : {
341 6 : nCnt++;
342 6 : pRef = ppKeys[ nCnt ];
343 6 : if( !*pRef )
344 0 : bSearch = false;
345 : }
346 : }
347 :
348 4 : if( *pRef )
349 4 : eS = S_VectorVal;
350 : else
351 0 : eS = S_UNKNOWN;
352 : }
353 4 : break;
354 : case S_VectorVal:
355 : {
356 4 : const sal_Unicode* pCur = aLine.getStr();
357 :
358 4 : pCur = ScanIntVal( pCur, nVector );
359 :
360 4 : if( pCur && *pCur == ',' )
361 : {
362 4 : pCur++;
363 4 : ScanIntVal( pCur, nVal );
364 4 : eS = S_Data;
365 : }
366 : else
367 0 : eS = S_ERROR_L2;
368 : }
369 4 : break;
370 : case S_Data:
371 : OSL_ENSURE( aLine.getLength() >= 2,
372 : "+GetNextTopic(): <String> is too short!" );
373 4 : if( aLine.getLength() > 2 )
374 1 : aData = aLine.copy( 1, aLine.getLength() - 2 );
375 : else
376 3 : aData.clear();
377 4 : eS = S_END;
378 4 : break;
379 : case S_END:
380 : OSL_FAIL( "DifParser::GetNextTopic - unexpected state" );
381 0 : break;
382 : case S_UNKNOWN:
383 : // skip 2 lines
384 0 : ReadNextLine( aLine );
385 : // fall-through
386 : case S_ERROR_L2: // error happened in line 2
387 : // skip 1 line
388 0 : ReadNextLine( aLine );
389 0 : eS = S_END;
390 0 : break;
391 : default:
392 : OSL_FAIL( "DifParser::GetNextTopic - missing enum" );
393 : }
394 : }
395 :
396 4 : return eRet;
397 : }
398 :
399 26 : static void lcl_DeEscapeQuotesDif( OUString& rString )
400 : {
401 : // Special handling for DIF import: Escaped (duplicated) quotes are resolved.
402 : // Single quote characters are left in place because older versions didn't
403 : // escape quotes in strings (and Excel doesn't when using the clipboard).
404 : // The quotes around the string are removed before this function is called.
405 :
406 26 : rString = rString.replaceAll("\"\"", "\"");
407 26 : }
408 :
409 : // Determine if passed in string is numeric data and set fVal/nNumFormat if so
410 10 : DATASET DifParser::GetNumberDataset( const sal_Unicode* pPossibleNumericData )
411 : {
412 10 : DATASET eRet = D_SYNT_ERROR;
413 10 : if( bPlain )
414 : {
415 0 : if( ScanFloatVal( pPossibleNumericData ) )
416 0 : eRet = D_NUMERIC;
417 : else
418 0 : eRet = D_SYNT_ERROR;
419 : }
420 : else
421 : { // ...and for punishment, with number formatting...
422 : OSL_ENSURE( pNumFormatter, "-DifParser::GetNextDataset(): No Formatter, more fun!" );
423 10 : OUString aTestVal( pPossibleNumericData );
424 10 : sal_uInt32 nFormat = 0;
425 : double fTmpVal;
426 10 : if( pNumFormatter->IsNumberFormat( aTestVal, nFormat, fTmpVal ) )
427 : {
428 10 : fVal = fTmpVal;
429 10 : nNumFormat = nFormat;
430 10 : eRet = D_NUMERIC;
431 : }
432 : else
433 0 : eRet = D_SYNT_ERROR;
434 : }
435 10 : return eRet;
436 : }
437 :
438 86 : bool DifParser::ReadNextLine( OUString& rStr )
439 : {
440 86 : if( aLookAheadLine.isEmpty() )
441 : {
442 60 : return rIn.ReadUniOrByteStringLine( rStr, rIn.GetStreamCharSet() );
443 : }
444 : else
445 : {
446 26 : rStr = aLookAheadLine;
447 26 : aLookAheadLine.clear();
448 26 : return true;
449 : }
450 : }
451 :
452 : // Look ahead in the stream to determine if the next line is the first line of
453 : // a valid data record structure
454 26 : bool DifParser::LookAhead()
455 : {
456 : const sal_Unicode* pAktBuffer;
457 26 : bool bValidStructure = false;
458 :
459 : OSL_ENSURE( aLookAheadLine.isEmpty(), "*DifParser::LookAhead(): LookAhead called twice in a row" );
460 26 : rIn.ReadUniOrByteStringLine( aLookAheadLine, rIn.GetStreamCharSet() );
461 :
462 26 : pAktBuffer = aLookAheadLine.getStr();
463 :
464 26 : switch( *pAktBuffer )
465 : {
466 : case '-': // Special Datatype
467 4 : pAktBuffer++;
468 :
469 4 : if( Is1_0( pAktBuffer ) )
470 : {
471 4 : bValidStructure = true;
472 : }
473 4 : break;
474 : case '0': // Numeric Data
475 4 : pAktBuffer++;
476 4 : if( *pAktBuffer == ',' )
477 : {
478 4 : pAktBuffer++;
479 4 : bValidStructure = ( GetNumberDataset(pAktBuffer) != D_SYNT_ERROR );
480 : }
481 4 : break;
482 : case '1': // String Data
483 18 : if( Is1_0( aLookAheadLine.getStr() ) )
484 : {
485 18 : bValidStructure = true;
486 : }
487 18 : break;
488 : }
489 26 : return bValidStructure;
490 : }
491 :
492 37 : DATASET DifParser::GetNextDataset()
493 : {
494 37 : DATASET eRet = D_UNKNOWN;
495 37 : OUString aLine;
496 : const sal_Unicode* pAktBuffer;
497 :
498 37 : ReadNextLine( aLine );
499 :
500 37 : pAktBuffer = aLine.getStr();
501 :
502 37 : switch( *pAktBuffer )
503 : {
504 : case '-': // Special Datatype
505 5 : pAktBuffer++;
506 :
507 5 : if( Is1_0( pAktBuffer ) )
508 : {
509 5 : ReadNextLine( aLine );
510 5 : if( IsBOT( aLine.getStr() ) )
511 4 : eRet = D_BOT;
512 1 : else if( IsEOD( aLine.getStr() ) )
513 1 : eRet = D_EOD;
514 : }
515 5 : break;
516 : case '0': // Numeric Data
517 6 : pAktBuffer++; // value in fVal, 2. line in aData
518 6 : if( *pAktBuffer == ',' )
519 : {
520 6 : pAktBuffer++;
521 6 : eRet = GetNumberDataset(pAktBuffer);
522 6 : OUString aTmpLine;
523 6 : ReadNextLine( aTmpLine );
524 6 : if ( eRet == D_SYNT_ERROR )
525 : { // for broken records write "#ERR: data" to cell
526 0 : OUStringBuffer aTmp("#ERR: ");
527 0 : aTmp.append(pAktBuffer).append(" (");
528 0 : aTmp.append(aTmpLine).append(')');
529 0 : aData = aTmp.makeStringAndClear();
530 0 : eRet = D_STRING;
531 : }
532 : else
533 : {
534 6 : aData = aTmpLine;
535 6 : }
536 : }
537 6 : break;
538 : case '1': // String Data
539 26 : if( Is1_0( aLine.getStr() ) )
540 : {
541 26 : ReadNextLine( aLine );
542 26 : sal_Int32 nLineLength = aLine.getLength();
543 26 : const sal_Unicode* pLine = aLine.getStr();
544 :
545 26 : if( nLineLength >= 1 && *pLine == '"' )
546 : {
547 : // Quotes are not always escaped (duplicated), see lcl_DeEscapeQuotesDif
548 : // A look ahead into the next line is needed in order to deal with
549 : // multiline strings containing quotes
550 26 : if( LookAhead() )
551 : {
552 : // Single line string
553 26 : if( nLineLength >= 2 && pLine[nLineLength - 1] == '"' )
554 : {
555 26 : aData = aLine.copy( 1, nLineLength - 2 );
556 26 : lcl_DeEscapeQuotesDif( aData );
557 26 : eRet = D_STRING;
558 : }
559 : }
560 : else
561 : {
562 : // Multiline string
563 0 : aData = aLine.copy( 1 );
564 0 : bool bContinue = true;
565 0 : while ( bContinue )
566 : {
567 0 : aData = aData + "\n";
568 0 : bContinue = !rIn.IsEof() && ReadNextLine( aLine );
569 0 : if( bContinue )
570 : {
571 0 : nLineLength = aLine.getLength();
572 0 : if( nLineLength >= 1 )
573 : {
574 0 : pLine = aLine.getStr();
575 0 : bContinue = !LookAhead();
576 0 : if( bContinue )
577 : {
578 0 : aData = aData + aLine;
579 : }
580 0 : else if( pLine[nLineLength - 1] == '"' )
581 : {
582 0 : aData = aData + aLine.copy(0, nLineLength -1 );
583 0 : lcl_DeEscapeQuotesDif( aData );
584 0 : eRet = D_STRING;
585 : }
586 : }
587 : }
588 : }
589 : }
590 : }
591 : }
592 26 : break;
593 : }
594 :
595 37 : if( eRet == D_UNKNOWN )
596 0 : ReadNextLine( aLine );
597 :
598 37 : if( rIn.IsEof() )
599 0 : eRet = D_EOD;
600 :
601 37 : return eRet;
602 : }
603 :
604 8 : const sal_Unicode* DifParser::ScanIntVal( const sal_Unicode* pStart, sal_uInt32& rRet )
605 : {
606 : // eat leading whitespace, not specified, but seen in the wild
607 16 : while (*pStart == ' ' || *pStart == '\t')
608 0 : ++pStart;
609 :
610 8 : sal_Unicode cAkt = *pStart;
611 :
612 8 : if( IsNumber( cAkt ) )
613 8 : rRet = ( sal_uInt32 ) ( cAkt - '0' );
614 : else
615 0 : return NULL;
616 :
617 8 : pStart++;
618 8 : cAkt = *pStart;
619 :
620 16 : while( IsNumber( cAkt ) && rRet < ( 0xFFFFFFFF / 10 ) )
621 : {
622 0 : rRet *= 10;
623 0 : rRet += ( sal_uInt32 ) ( cAkt - '0' );
624 :
625 0 : pStart++;
626 0 : cAkt = *pStart;
627 : }
628 :
629 8 : return pStart;
630 : }
631 :
632 0 : bool DifParser::ScanFloatVal( const sal_Unicode* pStart )
633 : {
634 0 : bool bNeg = false;
635 0 : double fFracPos = 1.0;
636 0 : sal_Int32 nExp = 0;
637 0 : bool bExpNeg = false;
638 0 : bool bExpOverflow = false;
639 : static const sal_uInt16 nExpLimit = 4096; // FIXME: has to be set more accurately!
640 :
641 : sal_Unicode cAkt;
642 0 : bool bRet = false;
643 :
644 : enum STATE { S_FIRST, S_PRE, S_POST, S_EXP_FIRST, S_EXP, S_END, S_FINDEND };
645 :
646 0 : STATE eS = S_FIRST;
647 :
648 0 : double fNewVal = 0.0;
649 :
650 0 : while( eS != S_END )
651 : {
652 0 : cAkt = *pStart;
653 0 : switch( eS )
654 : {
655 : case S_FIRST:
656 0 : if( IsNumber( cAkt ) )
657 : {
658 0 : fNewVal *= 10;
659 0 : fNewVal += cAkt - '0';
660 0 : eS = S_PRE;
661 : }
662 : else
663 : {
664 0 : switch( cAkt )
665 : {
666 : case ' ':
667 : case '\t':
668 : case '+':
669 0 : break;
670 : case '-':
671 0 : bNeg = !bNeg;
672 0 : break;
673 : case '.':
674 : case ',':
675 0 : eS = S_POST;
676 0 : fFracPos = 0.1;
677 0 : break;
678 : default:
679 0 : eS = S_END;
680 : }
681 : }
682 0 : break;
683 : case S_PRE:
684 0 : if( IsNumber( cAkt ) )
685 : {
686 0 : fNewVal *= 10;
687 0 : fNewVal += cAkt - '0';
688 : }
689 : else
690 : {
691 0 : switch( cAkt )
692 : {
693 : case '.':
694 : case ',':
695 0 : eS = S_POST;
696 0 : fFracPos = 0.1;
697 0 : break;
698 : case 'e':
699 : case 'E':
700 0 : eS = S_EXP;
701 0 : break;
702 : case 0x00: // IsNumberEnding( cAkt )
703 0 : bRet = true; // no
704 : default: // break!
705 0 : eS = S_END;
706 : }
707 : }
708 0 : break;
709 : case S_POST:
710 0 : if( IsNumber( cAkt ) )
711 : {
712 0 : fNewVal += fFracPos * ( cAkt - '0' );
713 0 : fFracPos /= 10.0;
714 : }
715 : else
716 : {
717 0 : switch( cAkt )
718 : {
719 : case 'e':
720 : case 'E':
721 0 : eS = S_EXP_FIRST;
722 0 : break;
723 : case 0x00: // IsNumberEnding( cAkt )
724 0 : bRet = true; // no
725 : default: // break!
726 0 : eS = S_END;
727 : }
728 : }
729 0 : break;
730 : case S_EXP_FIRST:
731 0 : if( IsNumber( cAkt ) )
732 : {
733 0 : if( nExp < nExpLimit )
734 : {
735 0 : nExp *= 10;
736 0 : nExp += ( sal_uInt16 ) ( cAkt - '0' );
737 : }
738 0 : eS = S_EXP;
739 : }
740 : else
741 : {
742 0 : switch( cAkt )
743 : {
744 : case '+':
745 0 : break;
746 : case '-':
747 0 : bExpNeg = !bExpNeg;
748 0 : break;
749 : default:
750 0 : eS = S_END;
751 : }
752 : }
753 0 : break;
754 : case S_EXP:
755 0 : if( IsNumber( cAkt ) )
756 : {
757 0 : if( nExp < ( 0xFFFF / 10 ) )
758 : {
759 0 : nExp *= 10;
760 0 : nExp += ( sal_uInt16 ) ( cAkt - '0' );
761 : }
762 : else
763 : {
764 0 : bExpOverflow = true;
765 0 : eS = S_FINDEND;
766 : }
767 : }
768 : else
769 : {
770 0 : bRet = IsNumberEnding( cAkt );
771 0 : eS = S_END;
772 : }
773 0 : break;
774 : case S_FINDEND:
775 0 : if( IsNumberEnding( cAkt ) )
776 : {
777 0 : bRet = true; // to continue parsing
778 0 : eS = S_END;
779 : }
780 0 : break;
781 : case S_END:
782 : OSL_FAIL( "DifParser::ScanFloatVal - unexpected state" );
783 0 : break;
784 : default:
785 : OSL_FAIL( "DifParser::ScanFloatVal - missing enum" );
786 : }
787 0 : pStart++;
788 : }
789 :
790 0 : if( bRet )
791 : {
792 0 : if( bExpOverflow )
793 0 : return false; // FIXME: add special cases here
794 :
795 0 : if( bNeg )
796 0 : fNewVal *= 1.0;
797 :
798 0 : if( bExpNeg )
799 0 : nExp *= -1;
800 :
801 0 : if( nExp != 0 )
802 0 : fNewVal *= pow( 10.0, ( double ) nExp );
803 0 : fVal = fNewVal;
804 : }
805 :
806 0 : return bRet;
807 : }
808 :
809 2 : DifColumn::DifColumn ()
810 2 : : pAkt(NULL)
811 : {
812 2 : }
813 :
814 0 : void DifColumn::SetLogical( SCROW nRow )
815 : {
816 : OSL_ENSURE( ValidRow(nRow), "*DifColumn::SetLogical(): Row too big!" );
817 :
818 0 : if( pAkt )
819 : {
820 : OSL_ENSURE( nRow > 0, "*DifColumn::SetLogical(): more cannot be zero!" );
821 :
822 0 : nRow--;
823 :
824 0 : if( pAkt->nEnd == nRow )
825 0 : pAkt->nEnd++;
826 : else
827 0 : pAkt = NULL;
828 : }
829 : else
830 : {
831 0 : pAkt = new ENTRY;
832 0 : pAkt->nStart = pAkt->nEnd = nRow;
833 :
834 0 : aEntries.push_back(pAkt);
835 : }
836 0 : }
837 :
838 6 : void DifColumn::SetNumFormat( SCROW nRow, const sal_uInt32 nNumFormat )
839 : {
840 : OSL_ENSURE( ValidRow(nRow), "*DifColumn::SetNumFormat(): Row too big!" );
841 :
842 6 : if( nNumFormat > 0 )
843 : {
844 0 : if(pAkt)
845 : {
846 : OSL_ENSURE( nRow > 0,
847 : "*DifColumn::SetNumFormat(): more cannot be zero!" );
848 : OSL_ENSURE( nRow > pAkt->nEnd,
849 : "*DifColumn::SetNumFormat(): start from scratch?" );
850 :
851 0 : if( pAkt->nNumFormat == nNumFormat && pAkt->nEnd == nRow - 1 )
852 0 : pAkt->nEnd = nRow;
853 : else
854 0 : NewEntry( nRow, nNumFormat );
855 : }
856 : else
857 0 : NewEntry(nRow,nNumFormat );
858 : }
859 : else
860 6 : pAkt = NULL;
861 6 : }
862 :
863 0 : void DifColumn::NewEntry( const SCROW nPos, const sal_uInt32 nNumFormat )
864 : {
865 0 : pAkt = new ENTRY;
866 0 : pAkt->nStart = pAkt->nEnd = nPos;
867 0 : pAkt->nNumFormat = nNumFormat;
868 :
869 0 : aEntries.push_back(pAkt);
870 0 : }
871 :
872 0 : void DifColumn::Apply( ScDocument& rDoc, const SCCOL nCol, const SCTAB nTab, const ScPatternAttr& rPattAttr )
873 : {
874 0 : for (boost::ptr_vector<ENTRY>::const_iterator it = aEntries.begin(); it != aEntries.end(); ++it)
875 0 : rDoc.ApplyPatternAreaTab( nCol, it->nStart, nCol, it->nEnd, nTab, rPattAttr );
876 0 : }
877 :
878 2 : void DifColumn::Apply( ScDocument& rDoc, const SCCOL nCol, const SCTAB nTab )
879 : {
880 2 : ScPatternAttr aAttr( rDoc.GetPool() );
881 2 : SfxItemSet &rItemSet = aAttr.GetItemSet();
882 :
883 2 : for (boost::ptr_vector<ENTRY>::const_iterator it = aEntries.begin(); it != aEntries.end(); ++it)
884 : {
885 : OSL_ENSURE( it->nNumFormat > 0,
886 : "+DifColumn::Apply(): Number format must not be 0!" );
887 :
888 0 : rItemSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, it->nNumFormat ) );
889 :
890 0 : rDoc.ApplyPatternAreaTab( nCol, it->nStart, nCol, it->nEnd, nTab, aAttr );
891 :
892 0 : rItemSet.ClearItem();
893 2 : }
894 2 : }
895 :
896 1 : DifAttrCache::DifAttrCache( const bool bNewPlain )
897 : {
898 1 : bPlain = bNewPlain;
899 1 : ppCols = new DifColumn *[ MAXCOL + 1 ];
900 1025 : for( SCCOL nCnt = 0 ; nCnt <= MAXCOL ; nCnt++ )
901 1024 : ppCols[ nCnt ] = NULL;
902 1 : }
903 :
904 1 : DifAttrCache::~DifAttrCache()
905 : {
906 1025 : for( SCCOL nCnt = 0 ; nCnt <= MAXCOL ; nCnt++ )
907 : {
908 1024 : if( ppCols[ nCnt ] )
909 2 : delete ppCols[ nCnt ];
910 : }
911 :
912 1 : delete[] ppCols;
913 1 : }
914 :
915 0 : void DifAttrCache::SetLogical( const SCCOL nCol, const SCROW nRow )
916 : {
917 : OSL_ENSURE( ValidCol(nCol), "-DifAttrCache::SetLogical(): Col too big!" );
918 : OSL_ENSURE( bPlain, "*DifAttrCache::SetLogical(): has to be Plain!" );
919 :
920 0 : if( !ppCols[ nCol ] )
921 0 : ppCols[ nCol ] = new DifColumn;
922 :
923 0 : ppCols[ nCol ]->SetLogical( nRow );
924 0 : }
925 :
926 6 : void DifAttrCache::SetNumFormat( const SCCOL nCol, const SCROW nRow, const sal_uInt32 nNumFormat )
927 : {
928 : OSL_ENSURE( ValidCol(nCol), "-DifAttrCache::SetNumFormat(): Col too big!" );
929 : OSL_ENSURE( !bPlain, "*DifAttrCache::SetNumFormat(): should not be Plain!" );
930 :
931 6 : if( !ppCols[ nCol ] )
932 2 : ppCols[ nCol ] = new DifColumn;
933 :
934 6 : ppCols[ nCol ]->SetNumFormat( nRow, nNumFormat );
935 6 : }
936 :
937 1 : void DifAttrCache::Apply( ScDocument& rDoc, SCTAB nTab )
938 : {
939 1 : if( bPlain )
940 : {
941 0 : boost::scoped_ptr<ScPatternAttr> pPatt;
942 :
943 0 : for( SCCOL nCol = 0 ; nCol <= MAXCOL ; nCol++ )
944 : {
945 0 : if( ppCols[ nCol ] )
946 : {
947 0 : if( !pPatt )
948 : {
949 0 : pPatt.reset(new ScPatternAttr( rDoc.GetPool() ));
950 0 : pPatt->GetItemSet().Put( SfxUInt32Item( ATTR_VALUE_FORMAT,
951 0 : rDoc.GetFormatTable()->GetStandardFormat( css::util::NumberFormat::LOGICAL ) ) );
952 : }
953 :
954 0 : ppCols[ nCol ]->Apply( rDoc, nCol, nTab, *pPatt );
955 : }
956 0 : }
957 : }
958 : else
959 : {
960 1025 : for( SCCOL nCol = 0 ; nCol <= MAXCOL ; nCol++ )
961 : {
962 1024 : if( ppCols[ nCol ] )
963 2 : ppCols[ nCol ]->Apply( rDoc, nCol, nTab );
964 : }
965 : }
966 31 : }
967 :
968 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|