filters

excel.cpp
1/* Swinder - Portable library for spreadsheet
2 Copyright (C) 2003-2006 Ariya Hidayat <ariya@kde.org>
3 Copyright (C) 2006 Marijn Kruisselbrink <m.kruisselbrink@student.tue.nl>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA
19*/
20
21#include "excel.h"
22
23#include <iostream>
24#include <iomanip>
25#include <vector>
26#include <string>
27#include <map>
28#include <stdio.h> // memcpy
29#include <string.h>
30#include <stdlib.h>
31
32#include "pole.h"
33#include "swinder.h"
34
35// Use anonymous namespace to cover following functions
36namespace{
37
38static inline unsigned long readU16( const void* p )
39{
40 const unsigned char* ptr = (const unsigned char*) p;
41 return ptr[0]+(ptr[1]<<8);
42}
43
44static inline int readI16( const void* p )
45{
46 const unsigned char* ptr = (const unsigned char*) p;
47 unsigned int v = ptr[0]+(ptr[1]<<8);
48 if(v > 32768) v -= 65536;
49 return v;
50}
51
52static inline unsigned long readU32( const void* p )
53{
54 const unsigned char* ptr = (const unsigned char*) p;
55 return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24);
56}
57
58typedef double& data_64;
59inline void convert_64 (data_64 convert)
60{
61 unsigned char temp;
62 unsigned int u_int_temp;
63 temp = ((unsigned char*)&convert)[0];
64 ((unsigned char*)&convert)[0] = ((unsigned char*)&convert)[3];
65 ((unsigned char*)&convert)[3] = temp;
66 temp = ((unsigned char*)&convert)[1];
67 ((unsigned char*)&convert)[1] = ((unsigned char*)&convert)[2];
68 ((unsigned char*)&convert)[2] = temp;
69 temp = ((unsigned char*)&convert)[4];
70 ((unsigned char*)&convert)[4] = ((unsigned char*)&convert)[7];
71 ((unsigned char*)&convert)[7] = temp;
72 temp = ((unsigned char*)&convert)[5];
73 ((unsigned char*)&convert)[5] = ((unsigned char*)&convert)[6];
74 ((unsigned char*)&convert)[6] = temp;
75
76 u_int_temp = ((unsigned int *)&convert)[0];
77 ((unsigned int *)&convert)[0] = ((unsigned int *)&convert)[1];
78 ((unsigned int *)&convert)[1] = u_int_temp;
79}
80
81inline bool isLittleEndian(void)
82{
83 long i = 0x44332211;
84 unsigned char* a = (unsigned char*) &i;
85 return ( *a == 0x11 );
86}
87
88
89// FIXME check that double is 64 bits
90static inline double readFloat64( const void*p )
91{
92 const double* ptr = (const double*) p;
93 double num = 0.0;
94 num = *ptr;
95
96 if( !isLittleEndian() )
97 convert_64( num );
98
99 return num;
100}
101
102// RK value is special encoded integer or floating-point
103// see any documentation of Excel file format for detail description
104static inline void decodeRK( unsigned rkvalue, bool& isInteger,
105 int& intResult, double& floatResult )
106{
107 bool div100 = rkvalue & 0x01;
108 isInteger = rkvalue & 0x02;
109
110 if( isInteger )
111 {
112 // FIXME check that int is 32 bits ?
113 intResult = *((int*) &rkvalue) >> 2;
114
115 // divide by 100, fall to floating-point
116 if(div100)
117 {
118 isInteger = false;
119 floatResult = (double)intResult / 100.0;
120 }
121 }
122 else
123 {
124 // TODO ensure double takes 8 bytes
125 unsigned char* s = (unsigned char*) &rkvalue;
126 unsigned char* r = (unsigned char*) &floatResult;
127 if( isLittleEndian() )
128 {
129 r[0] = r[1] = r[2] = r[3] = 0;
130 r[4] = s[0] & 0xfc;
131 r[5] = s[1]; r[6] = s[2]; r[7] = s[3];
132 }
133 else
134 {
135 r[0] = r[1] = r[2] = r[3] = 0;
136 r[4] = s[0] & 0xfc;
137 r[5] = s[1]; r[6] = s[2]; r[7] = s[3];
138 }
139 memcpy( &floatResult, r, 8 );
140
141 if( div100 )
142 floatResult *= 0.01;
143 }
144}
145
146}
147
148namespace Swinder
149{
150std::ostream& operator<<( std::ostream& s, Swinder::UString ustring )
151{
152 char* str = ustring.ascii();
153 s << str;
154 return s;
155}
156
157}
158
159using namespace Swinder;
160
161static Value errorAsValue( int errorCode )
162{
163 Value result( Value::Error );
164
165 switch( errorCode )
166 {
167 case 0x00: result = Value::errorNULL(); break;
168 case 0x07: result = Value::errorDIV0(); break;
169 case 0x0f: result = Value::errorVALUE(); break;
170 case 0x17: result = Value::errorREF(); break;
171 case 0x1d: result = Value::errorNAME(); break;
172 case 0x24: result = Value::errorNUM(); break;
173 case 0x2A: result = Value::errorNA(); break;
174 default: break;
175 };
176
177 return result;
178}
179
180//=============================================
181// EString
182//=============================================
183
184
185class EString::Private
186{
187public:
188 bool unicode;
189 bool richText;
190 UString str;
191 unsigned size;
192};
193
194EString::EString()
195{
196 d = new EString::Private();
197 d->unicode = false;
198 d->richText = false;
199 d->str = UString::null;
200 d->size = 0;
201}
202
203EString::EString( const EString& es )
204{
205 d = new EString::Private();
206 operator=( es );
207}
208
209EString& EString::operator=( const EString& es )
210{
211 d->unicode = es.d->unicode;
212 d->richText = es.d->richText;
213 d->size = es.d->size;
214 d->str = es.d->str;
215 return *this;
216}
217
218EString::~EString()
219{
220 delete d;
221}
222
223bool EString::unicode() const
224{
225 return d->unicode;
226}
227
228void EString::setUnicode( bool u )
229{
230 d->unicode = u;
231}
232
233bool EString::richText() const
234{
235 return d->richText;
236}
237
238void EString::setRichText( bool r )
239{
240 d->richText = r;
241}
242
243UString EString::str() const
244{
245 return d->str;
246}
247
248void EString::setStr( const UString& str )
249{
250 d->str = str;
251}
252
253unsigned EString::size() const
254{
255 return d->size;
256}
257
258void EString::setSize( unsigned s )
259{
260 d->size = s;
261}
262
263// FIXME use maxsize for sanity check
264EString EString::fromUnicodeString( const void* p, bool longString, unsigned /* maxsize */ )
265{
266 const unsigned char* data = (const unsigned char*) p;
267 UString str = UString::null;
268
269 unsigned offset = longString ? 2 : 1;
270 unsigned len = longString ? readU16( data ): data[0];
271 unsigned char flag = data[ offset ];
272 offset++; // for flag (1 byte)
273
274 bool unicode = flag & 0x01;
275 bool richText = flag & 0x08;
276 unsigned formatRuns = 0;
277
278 if( richText )
279 {
280 formatRuns = readU16( data + offset );
281 offset += 2;
282 }
283
284 // find out total bytes used in this string
285 unsigned size = offset + len; // string data
286 if( unicode ) size += len; // because unicode takes 2-bytes char
287 if( richText ) size += (formatRuns*4);
288
289 if( !unicode )
290 {
291 char* buffer = new char[ len+1 ];
292 memcpy( buffer, data + offset, len );
293 buffer[ len ] = 0;
294 str = UString( buffer );
295 delete[] buffer;
296 }
297 else
298 {
299 str = UString();
300 str.reserve(len);
301 for( unsigned k=0; k<len; k++ )
302 str.append( readU16( data + offset + k*2 ) );
303 }
304
305 EString result;
306 result.setUnicode( unicode );
307 result.setRichText( richText );
308 result.setSize( size );
309 result.setStr( str );
310
311 return result;
312}
313
314// FIXME use maxsize for sanity check
315EString EString::fromByteString( const void* p, bool longString,
316 unsigned /* maxsize */ )
317{
318 const unsigned char* data = (const unsigned char*) p;
319 UString str = UString::null;
320
321 unsigned offset = longString ? 2 : 1;
322 unsigned len = longString ? readU16( data ): data[0];
323
324 char* buffer = new char[ len+1 ];
325 memcpy( buffer, data + offset, len );
326 buffer[ len ] = 0;
327 str = UString( buffer );
328 delete[] buffer;
329
330 unsigned size = offset + len;
331
332 EString result;
333 result.setUnicode( false );
334 result.setRichText( false );
335 result.setSize( size );
336 result.setStr( str );
337
338 return result;
339}
340
341
342
343// why different ? see BoundSheetRecord
344EString EString::fromSheetName( const void* p, unsigned datasize )
345{
346 const unsigned char* data = (const unsigned char*) p;
347 UString str = UString::null;
348
349 bool richText = false;
350 // unsigned formatRuns = 0;
351
352 unsigned len = data[0];
353 unsigned flag = data[1];
354 bool unicode = flag & 1;
355
356 if( len > datasize-2 ) len = datasize-2;
357 if( len == 0 ) return EString();
358
359 unsigned offset = 2;
360
361 if( !unicode )
362 {
363 char* buffer = new char[ len+1 ];
364 memcpy( buffer, data + offset, len );
365 buffer[ len ] = 0;
366 str = UString( buffer );
367 delete[] buffer;
368 }
369 else
370 {
371 for( unsigned k=0; k<len; k++ )
372 {
373 unsigned uch = readU16( data + offset + k*2 );
374 str.append( UChar(uch) );
375 }
376 }
377
378 EString result;
379 result.setUnicode( unicode );
380 result.setRichText( richText );
381 result.setSize( datasize );
382 result.setStr( str );
383
384 return result;
385}
386
387//=============================================
388// FormulaToken
389//=============================================
390
391class FormulaToken::Private
392{
393public:
394 unsigned ver;
395 unsigned id;
396 std::vector<unsigned char> data;
397};
398
399FormulaToken::FormulaToken()
400{
401 d = new Private;
402 d->ver = Excel97;
403 d->id = Unused;
404}
405
406FormulaToken::FormulaToken( unsigned t )
407{
408 d = new Private;
409 d->ver = Excel97;
410 d->id = t;
411}
412
413FormulaToken::FormulaToken( const FormulaToken& token )
414{
415 d = new Private;
416 d->ver = token.d->ver;
417 d->id = token.id();
418
419 d->data.resize( token.d->data.size() );
420 for( unsigned i = 0; i < d->data.size(); i++ )
421 d->data[i] = token.d->data[i];
422}
423
424FormulaToken::~FormulaToken()
425{
426 delete d;
427}
428
429unsigned FormulaToken::version() const
430{
431 return d->ver;
432}
433
434void FormulaToken::setVersion( unsigned v )
435{
436 d->ver = v;
437}
438
439unsigned FormulaToken::id() const
440{
441 return d->id;
442}
443
444const char* FormulaToken::idAsString() const
445{
446 const char* s = 0;
447
448 switch( d->id )
449 {
450 case Matrix: s = "Matrix"; break;
451 case Table: s = "Table"; break;
452 case Add: s = "Add"; break;
453 case Sub: s = "Sub"; break;
454 case Mul: s = "Mul"; break;
455 case Div: s = "Div"; break;
456 case Power: s = "Power"; break;
457 case Concat: s = "Concat"; break;
458 case LT: s = "LT"; break;
459 case LE: s = "LE"; break;
460 case EQ: s = "EQ"; break;
461 case GE: s = "GE"; break;
462 case GT: s = "GT"; break;
463 case NE: s = "NE"; break;
464 case Intersect: s = "Intersect"; break;
465 case List: s = "List"; break;
466 case Range: s = "Range"; break;
467 case UPlus: s = "UPlus"; break;
468 case UMinus: s = "UMinus"; break;
469 case Percent: s = "Percent"; break;
470 case Paren: s = "Paren"; break;
471 case String: s = "String"; break;
472 case MissArg: s = "MissArg"; break;
473 case ErrorCode: s = "ErrorCode"; break;
474 case Bool: s = "Bool"; break;
475 case Integer: s = "Integer"; break;
476 case Array: s = "Array"; break;
477 case Function: s = "Function"; break;
478 case FunctionVar: s = "FunctionVar"; break;
479 case Name: s = "Name"; break;
480 case Ref: s = "Ref"; break;
481 case RefErr: s = "RefErr"; break;
482 case RefN: s = "RefN"; break;
483 case Area: s = "Area"; break;
484 case AreaErr: s = "AreaErr"; break;
485 case AreaN: s = "AreaN"; break;
486 case NameX: s = "NameX"; break;
487 case Ref3d: s = "Ref3d"; break;
488 case RefErr3d: s = "RefErr3d"; break;
489 case Float: s = "Float"; break;
490 case Area3d: s = "Area3d"; break;
491 case AreaErr3d: s = "AreaErr3d"; break;
492 default: s = "Unknown"; break;
493 };
494
495 return s;
496}
497
498
499unsigned FormulaToken::size() const
500{
501 unsigned s = 0; // on most cases no data
502
503 switch( d->id )
504 {
505 case Add:
506 case Sub:
507 case Mul:
508 case Div:
509 case Power:
510 case Concat:
511 case LT:
512 case LE:
513 case EQ:
514 case GE:
515 case GT:
516 case NE:
517 case Intersect:
518 case List:
519 case Range:
520 case UPlus:
521 case UMinus:
522 case Percent:
523 case Paren:
524 case MissArg:
525 s = 0; break;
526
527 case Attr:
528 s = 3; break;
529
530 case ErrorCode:
531 case Bool:
532 s = 1; break;
533
534 case Integer:
535 s = 2; break;
536
537 case Array:
538 s = 7; break;
539
540 case Function:
541 s = 2;
542 break;
543
544 case FunctionVar:
545 s = 3;
546 break;
547
548 case Matrix:
549 case Table:
550 s = (d->ver == Excel97) ? 4 : 3;
551 break;
552
553 case Name:
554 s = (d->ver == Excel97) ? 4 : 14;
555 break;
556
557 case Ref:
558 case RefErr:
559 case RefN:
560 s = (d->ver == Excel97) ? 4 : 3;
561 break;
562
563 case Area:
564 case AreaErr:
565 case AreaN:
566 s = (d->ver == Excel97) ? 8 : 6;
567 break;
568
569 case NameX:
570 s = (d->ver == Excel97) ? 6 : 24;
571 break;
572
573 case Ref3d:
574 case RefErr3d:
575 s = (d->ver == Excel97) ? 6 : 17;
576 break;
577
578 case Float:
579 s = 8; break;
580
581 case Area3d:
582 case AreaErr3d:
583 s = (d->ver == Excel97) ? 10 : 20;
584 break;
585
586 default:
587 // WARNING this is unhandled case
588 break;
589 };
590
591 return s;
592}
593
594void FormulaToken::setData( unsigned size, const unsigned char* data )
595{
596 d->data.resize( size );
597 for( unsigned i = 0; i < size; i++ )
598 d->data[i] = data[i];
599}
600
601Value FormulaToken::value() const
602{
603 // sentinel
604 if(d->data.size() == 0)
605 return Value::empty();
606
607 Value result;
608
609 unsigned char* buf;
610 buf = new unsigned char[d->data.size()];
611 for( unsigned k=0; k<d->data.size(); k++ )
612 buf[k] = d->data[k];
613
614 // FIXME sanity check: verify size of data
615 switch( d->id )
616 {
617 case ErrorCode:
618 result = errorAsValue( buf[0] );
619 break;
620
621 case Bool:
622 result = Value( buf[0]!=0 );
623 break;
624
625 case Integer:
626 result = Value( (int)readU16( buf ) );
627 break;
628
629 case Float:
630 result = Value( readFloat64( buf ) );
631 break;
632
633 case String:
634 {
635 EString estr = (version()==Excel97) ?
636 EString::fromUnicodeString( buf, false, d->data.size() ) :
637 EString::fromByteString( buf, false, d->data.size() );
638 result = Value( estr.str() );
639 }
640 break;
641
642 default: break;
643 }
644
645 delete [] buf;
646
647 return result;
648}
649
650unsigned FormulaToken::functionIndex() const
651{
652 // FIXME check data size
653 unsigned index = 0;
654 unsigned char buf[2];
655
656 if( d->id == Function )
657 {
658 buf[0] = d->data[0];
659 buf[1] = d->data[1];
660 index = readU16( buf );
661 }
662
663 if( d->id == FunctionVar )
664 {
665 buf[0] = d->data[1];
666 buf[1] = d->data[2];
667 index = readU16( buf );
668 }
669
670 return index;
671}
672
673struct FunctionEntry
674{
675 const char *name;
676 int params;
677};
678
679static const FunctionEntry FunctionEntries[] =
680{
681 { "COUNT", 1 }, // 0
682 { "IF", 0 }, // 1
683 { "ISNV", 1 }, // 2
684 { "ISERROR", 1 }, // 3
685 { "SUM", 0 }, // 4
686 { "AVERAGE", 0 }, // 5
687 { "MIN", 0 }, // 6
688 { "MAX", 0 }, // 7
689 { "ROW", 0 }, // 8
690 { "COLUMN", 0 }, // 9
691 { "NOVALUE", 0 }, // 10
692 { "NPV", 0 }, // 11
693 { "STDEV", 0 }, // 12
694 { "DOLLAR", 0 }, // 13
695 { "FIXED", 0 }, // 14
696 { "SIN", 1 }, // 15
697 { "COS", 1 }, // 16
698 { "TAN", 1 }, // 17
699 { "ATAN", 1 }, // 18
700 { "PI", 0 }, // 19
701 { "SQRT", 1 }, // 20
702 { "EXP", 1 }, // 21
703 { "LN", 1 }, // 22
704 { "LOG10", 1 }, // 23
705 { "ABS", 1 }, // 24
706 { "INT", 1 }, // 25
707 { "SIGN", 1 }, // 26
708 { "ROUND", 2 }, // 27
709 { "LOOKUP", 0 }, // 28
710 { "INDEX", 0 }, // 29
711 { "REPT", 2 }, // 30
712 { "MID", 3 }, // 31
713 { "LEN", 1 }, // 32
714 { "VALUE", 1 }, // 33
715 { "TRUE", 0 }, // 34
716 { "FALSE", 0 }, // 35
717 { "AND", 0 }, // 36
718 { "OR", 0 }, // 37
719 { "NOT", 1 }, // 38
720 { "MOD", 2 }, // 39
721 { "DCOUNT", 3 }, // 40
722 { "DSUM", 3 }, // 41
723 { "DAVERAGE", 3 }, // 42
724 { "DMIN", 3 }, // 43
725 { "DMAX", 3 }, // 44
726 { "DSTDEV", 3 }, // 45
727 { "VAR", 0 }, // 46
728 { "DVAR", 3 }, // 47
729 { "TEXT", 2 }, // 48
730 { "LINEST", 0 }, // 49
731 { "TREND", 0 }, // 50
732 { "LOGEST", 0 }, // 51
733 { "GROWTH", 0 }, // 52
734 { "GOTO", 0 }, // 53
735 { "HALT", 0 }, // 54
736 { "Unknown55", 0 }, // 55
737 { "PV", 0 }, // 56
738 { "FV", 0 }, // 57
739 { "NPER", 0 }, // 58
740 { "PMT", 0 }, // 59
741 { "RATE", 0 }, // 60
742 { "MIRR", 3 }, // 61
743 { "IRR", 0 }, // 62
744 { "RAND", 0 }, // 63
745 { "MATCH", 0 }, // 64
746 { "DATE", 3 }, // 65
747 { "TIME", 3 }, // 66
748 { "DAY", 1 }, // 67
749 { "MONTH", 1 }, // 68
750 { "YEAR", 1 }, // 69
751 { "DAYOFWEEK", 0 }, // 70
752 { "HOUR", 1 }, // 71
753 { "MIN", 1 }, // 72
754 { "SEC", 1 }, // 73
755 { "NOW", 0 }, // 74
756 { "AREAS", 1 }, // 75
757 { "ROWS", 1 }, // 76
758 { "COLUMNS", 1 }, // 77
759 { "OFFSET", 0 }, // 78
760 { "ABSREF", 2 }, // 79
761 { "RELREF", 0 }, // 80
762 { "ARGUMENT", 0 }, // 81
763 { "SEARCH", 0 }, // 82
764 { "TRANSPOSE", 1 }, // 83
765 { "ERROR", 0 }, // 84
766 { "STEP", 0 }, // 85
767 { "TYPE", 1 }, // 86
768 { "ECHO", 0 },
769 { "SETNAME", 0 },
770 { "CALLER", 0 },
771 { "DEREF", 0 },
772 { "WINDOWS", 0 },
773 { "SERIES", 4 },
774 { "DOCUMENTS", 0 },
775 { "ACTIVECELL", 0 },
776 { "SELECTION", 0 },
777 { "RESULT", 0 },
778 { "ATAN2", 2 }, // 97
779 { "ASIN", 1 }, // 98
780 { "ACOS", 1 }, // 99
781 { "CHOOSE", 0 }, // 100
782 { "HLOOKUP", 0 }, // 101
783 { "VLOOKUP", 0 }, // 102
784 { "LINKS", 0 },
785 { "INPUT", 0 },
786 { "ISREF", 1 }, // 105
787 { "GETFORMULA", 0 },
788 { "GETNAME", 0 },
789 { "SETVALUE", 0 },
790 { "LOG", 0 }, // 109
791 { "EXEC", 0 },
792 { "CHAR", 1 }, // 111
793 { "LOWER", 1 }, // 112
794 { "UPPER", 1 }, // 113
795 { "PROPER", 1 }, // 114
796 { "LEFT", 0 }, // 115
797 { "RIGHT", 0 }, // 116
798 { "EXACT", 2 }, // 117
799 { "TRIM", 1 }, // 118
800 { "REPLACE", 4 }, // 119
801 { "SUBSTITUTE", 0 }, // 120
802 { "CODE", 1 }, // 121
803 { "NAMES", 0 },
804 { "DIRECTORY", 0 },
805 { "FIND", 0 }, // 124
806 { "CELL", 0 }, // 125
807 { "ISERR", 1 }, // 126
808 { "ISTEXT", 1 }, // 127
809 { "ISNUMBER", 1 }, // 128
810 { "ISBLANK", 1 }, // 129
811 { "T", 1 }, // 130
812 { "N", 1 }, // 131
813 { "FOPEN", 0 },
814 { "FCLOSE", 0 },
815 { "FSIZE", 0 },
816 { "FREADLN", 0 },
817 { "FREAD", 0 },
818 { "FWRITELN", 0 },
819 { "FWRITE", 0 },
820 { "FPOS", 0 },
821 { "DATEVALUE", 1 }, // 140
822 { "TIMEVALUE", 1 }, // 141
823 { "SLN", 3 }, // 142
824 { "SYD", 4 }, // 143
825 { "DDB", 0 }, // 144
826 { "GETDEF", 0 },
827 { "REFTEXT", 0 },
828 { "TEXTREF", 0 },
829 { "INDIRECT", 0 }, // 148
830 { "REGISTER", 0 },
831 { "CALL", 0 },
832 { "ADDBAR", 0 },
833 { "ADDMENU", 0 },
834 { "ADDCOMMAND", 0 },
835 { "ENABLECOMMAND", 0 },
836 { "CHECKCOMMAND", 0 },
837 { "RENAMECOMMAND", 0 },
838 { "SHOWBAR", 0 },
839 { "DELETEMENU", 0 },
840 { "DELETECOMMAND", 0 },
841 { "GETCHARTITEM", 0 },
842 { "DIALOGBOX", 0 },
843 { "CLEAN", 1 }, // 162
844 { "MDETERM", 1 }, // 163
845 { "MINVERSE", 1 }, // 164
846 { "MMULT", 2 }, // 165
847 { "FILES", 0 },
848 { "IPMT", 0 }, // 167
849 { "PPMT", 0 }, // 168
850 { "COUNTA", 0 }, // 169
851 { "CANCELKEY", 1 },
852 { "Unknown171", 0 },
853 { "Unknown172", 0 },
854 { "Unknown173", 0 },
855 { "Unknown174", 0 },
856 { "INITIATE", 0 },
857 { "REQUEST", 0 },
858 { "POKE", 0 },
859 { "EXECUTE", 0 },
860 { "TERMINATE", 0 },
861 { "RESTART", 0 },
862 { "HELP", 0 },
863 { "GETBAR", 0 },
864 { "PRODUCT", 0 }, // 183
865 { "FACT", 1 }, // 184
866 { "GETCELL", 0 },
867 { "GETWORKSPACE", 0 },
868 { "GETWINDOW", 0 },
869 { "GETDOCUMENT", 0 },
870 { "DPRODUCT", 3 }, // 189
871 { "ISNONTEXT", 1 }, // 190
872 { "GETNOTE", 0 },
873 { "NOTE", 0 },
874 { "STDEVP", 0 }, // 193
875 { "VARP", 0 }, // 194
876 { "DSTDEVP", 3 }, // 195
877 { "DVARP", 3 }, // 196
878 { "TRUNC", 0 }, // 197
879 { "ISLOGICAL", 1 }, // 198
880 { "DCOUNTA", 3 }, // 199
881 { "DELETEBAR", 0 },
882 { "UNREGISTER", 0 },
883 { "Unknown202", 0 },
884 { "Unknown203", 0 },
885 { "USDOLLAR", 0 },
886 { "FINDB", 0 },
887 { "SEARCHB", 0 },
888 { "REPLACEB", 0 },
889 { "LEFTB", 0 },
890 { "RIGHTB", 0 },
891 { "MIDB", 0 },
892 { "LENB", 0 },
893 { "ROUNDUP", 2 }, // 212
894 { "ROUNDDOWN", 2 }, // 213
895 { "ASC", 0 },
896 { "DBCS", 0 },
897 { "RANK", 0 }, // 216
898 { "Unknown217", 0 },
899 { "Unknown218", 0 },
900 { "ADDRESS", 0 }, // 219
901 { "GETDIFFDATE360", 0 }, // 220
902 { "CURRENTDATE", 0 }, // 221
903 { "VBD", 0 }, // 222
904 { "Unknown223", 0 },
905 { "Unknown224", 0 },
906 { "Unknown225", 0 },
907 { "Unknown226", 0 },
908 { "MEDIAN", 0 }, // 227
909 { "SUMPRODUCT", 0 }, // 228
910 { "SINH", 1 }, // 229
911 { "COSH", 1 }, // 230
912 { "TANH", 1 }, // 231
913 { "ASINH", 1 }, // 232
914 { "ACOSH", 1 }, // 233
915 { "ATANH", 1 }, // 234
916 { "DGET", 3 }, // 235
917 { "CREATEOBJECT", 0 },
918 { "VOLATILE", 0 },
919 { "LASTERROR", 0 },
920 { "CUSTOMUNDO", 0 },
921 { "CUSTOMREPEAT", 0 },
922 { "FORMULACONVERT", 0 },
923 { "GETLINKINFO", 0 },
924 { "TEXTBOX", 0 },
925 { "INFO", 1 }, // 244
926 { "GROUP", 0 },
927 { "GETOBJECT", 0 },
928 { "DB", 0 }, // 247
929 { "PAUSE", 0 },
930 { "Unknown249", 0 },
931 { "Unknown250", 0 },
932 { "RESUME", 0 },
933 { "FREQUENCY", 2 }, // 252
934 { "ADDTOOLBAR", 0 },
935 { "DELETETOOLBAR", 0 },
936 { "Unknown255", 0 },
937 { "RESETTOOLBAR", 0 },
938 { "EVALUATE", 0 },
939 { "GETTOOLBAR", 0 },
940 { "GETTOOL", 0 },
941 { "SPELLINGCHECK", 0 },
942 { "ERRORTYPE", 1 }, // 261
943 { "APPTITLE", 0 },
944 { "WINDOWTITLE", 0 },
945 { "SAVETOOLBAR", 0 },
946 { "ENABLETOOL", 0 },
947 { "PRESSTOOL", 0 },
948 { "REGISTERID", 0 },
949 { "GETWORKBOOK", 0 },
950 { "AVEDEV", 0 }, // 269
951 { "BETADIST", 0 }, // 270
952 { "GAMMALN", 1 }, // 271
953 { "BETAINV", 0 }, // 272
954 { "BINOMDIST", 4 }, // 273
955 { "CHIDIST", 2 }, // 274
956 { "CHIINV", 2 }, // 275
957 { "COMBIN", 2 }, // 276
958 { "CONFIDENCE", 3 }, // 277
959 { "CRITBINOM", 3 }, // 278
960 { "EVEN", 1 }, // 279
961 { "EXPONDIST", 3 }, // 280
962 { "FDIST", 3 }, // 281
963 { "FINV", 3 }, // 282
964 { "FISHER", 1 }, // 283
965 { "FISHERINV", 1 }, // 284
966 { "FLOOR", 2 }, // 285
967 { "GAMMADIST", 4 }, // 286
968 { "GAMMAINV", 3 }, // 287
969 { "CEIL", 2 }, // 288
970 { "HYPGEOMDIST", 4 }, // 289
971 { "LOGNORMDIST", 3 }, // 290
972 { "LOGINV", 3 }, // 291
973 { "NEGBINOMDIST", 3 }, // 292
974 { "NORMDIST", 4 }, // 293
975 { "NORMSDIST", 1 }, // 294
976 { "NORMINV", 3 }, // 295
977 { "NORMSINV", 1 }, // 296
978 { "STANDARDIZE", 3 }, // 297
979 { "ODD", 1 }, // 298
980 { "PERMUT", 2 }, // 299
981 { "POISSON", 3 }, // 300
982 { "TDIST", 3 }, // 301
983 { "WEIBULL", 4 }, // 302
984 { "SUMXMY2", 2 }, // 303
985 { "SUMX2MY2", 2 }, // 304
986 { "SUMX2DY2", 2 }, // 305
987 { "CHITEST", 2 }, // 306
988 { "CORREL", 2 }, // 307
989 { "COVAR", 2 }, // 308
990 { "FORECAST", 3 }, // 309
991 { "FTEST", 2 }, // 310
992 { "INTERCEPT", 2 }, // 311
993 { "PEARSON", 2 }, // 312
994 { "RSQ", 2 }, // 313
995 { "STEYX", 2 }, // 314
996 { "SLOPE", 2 }, // 315
997 { "TTEST", 4 }, // 316
998 { "PROB", 0 }, // 317
999 { "DEVSQ", 0 }, // 318
1000 { "GEOMEAN", 0 }, // 319
1001 { "HARMEAN", 0 }, // 320
1002 { "SUMSQ", 0 }, // 321
1003 { "KURT", 0 }, // 322
1004 { "SKEW", 0 }, // 323
1005 { "ZTEST", 0 }, // 324
1006 { "LARGE", 2 }, // 325
1007 { "SMALL", 2 }, // 326
1008 { "QUARTILE", 2 }, // 327
1009 { "PERCENTILE", 2 }, // 328
1010 { "PERCENTRANK", 0 }, // 329
1011 { "MODALVALUE", 0 }, // 330
1012 { "TRIMMEAN", 2 }, // 331
1013 { "TINV", 2 }, // 332
1014 { "Unknown333", 0 },
1015 { "MOVIECOMMAND", 0 },
1016 { "GETMOVIE", 0 },
1017 { "CONCATENATE", 0 }, // 336
1018 { "POWER", 2 }, // 337
1019 { "PIVOTADDDATA", 0 },
1020 { "GETPIVOTTABLE", 0 },
1021 { "GETPIVOTFIELD", 0 },
1022 { "GETPIVOTITEM", 0 },
1023 { "RADIANS", 1 }, // 342
1024 { "DEGREES", 1 }, // 343
1025 { "SUBTOTAL", 0 }, // 344
1026 { "SUMIF", 0 }, // 345
1027 { "COUNTIF", 2 }, // 346
1028 { "COUNTBLANK", 1 }, // 347
1029 { "SCENARIOGET", 0 },
1030 { "OPTIONSLISTSGET", 0 },
1031 { "ISPMT", 4 },
1032 { "DATEDIF", 3 },
1033 { "DATESTRING", 0 },
1034 { "NUMBERSTRING", 0 },
1035 { "ROMAN", 0 }, // 354
1036 { "OPENDIALOG", 0 },
1037 { "SAVEDIALOG", 0 },
1038 { "VIEWGET", 0 },
1039 { "GETPIVOTDATA", 2 }, // 358
1040 { "HYPERLINK", 1 },
1041 { "PHONETIC", 0 },
1042 { "AVERAGEA", 0 }, // 361
1043 { "MAXA", 0 }, // 362
1044 { "MINA", 0 }, // 363
1045 { "STDEVPA", 0 }, // 364
1046 { "VARPA", 0 }, // 365
1047 { "STDEVA", 0 }, // 366
1048 { "VARA", 0 }, // 367
1049};
1050
1051const char* FormulaToken::functionName() const
1052{
1053 if( functionIndex() > 367 ) return 0;
1054 return FunctionEntries[ functionIndex() ].name;
1055}
1056
1057unsigned FormulaToken::functionParams() const
1058{
1059 unsigned params = 0;
1060
1061 if( d->id == Function )
1062 {
1063 if( functionIndex() > 367 ) return 0;
1064 params = FunctionEntries[ functionIndex() ].params;
1065 }
1066
1067 if( d->id == FunctionVar )
1068 {
1069 params = (unsigned)d->data[0];
1070 params &= 0x7f;
1071 }
1072
1073 return params;
1074}
1075
1076unsigned FormulaToken::attr() const
1077{
1078 unsigned attr = 0;
1079 if( d->id == Attr )
1080 {
1081 attr = (unsigned) d->data[0];
1082 }
1083 return attr;
1084}
1085
1086unsigned FormulaToken::nameIndex() const
1087{
1088 // FIXME check data size !
1089 unsigned ni = 0;
1090 unsigned char buf[2];
1091
1092 if( d->id == NameX )
1093 if( d->ver == Excel97 )
1094 {
1095 buf[0] = d->data[2];
1096 buf[1] = d->data[3];
1097 ni = readU16( buf );
1098 }
1099
1100 if( d->id == NameX )
1101 if( d->ver == Excel95 )
1102 {
1103 buf[0] = d->data[10];
1104 buf[1] = d->data[11];
1105 ni = readU16( buf );
1106 }
1107
1108 return ni;
1109}
1110
1111
1112UString FormulaToken::area( unsigned row, unsigned col ) const
1113{
1114 // sanity check
1115 if(id() != Area)
1116 if(id() != Area3d)
1117 return UString::null;
1118
1119 // check data size
1120 int minsize = 0;
1121 if((id() == Area3d))
1122 minsize = (version() == Excel97) ? 10 : 20;
1123 else if(id() == Area)
1124 minsize = (version() == Excel97) ? 8 : 6;
1125 if(d->data.size() < minsize)
1126 return UString::null;
1127
1128 unsigned char buf[2];
1129 int row1Ref, row2Ref, col1Ref, col2Ref;
1130 bool row1Relative, col1Relative;
1131 bool row2Relative, col2Relative;
1132
1133 if( version() == Excel97 )
1134 {
1135 int ofs = (id() == Area) ? 0 : 2;
1136
1137 buf[0] = d->data[ofs];
1138 buf[1] = d->data[ofs+1];
1139 row1Ref = readU16( buf );
1140
1141 buf[0] = d->data[ofs+2];
1142 buf[1] = d->data[ofs+3];
1143 row2Ref = readU16( buf );
1144
1145 buf[0] = d->data[ofs+4];
1146 buf[1] = d->data[ofs+5];
1147 col1Ref = readU16( buf );
1148
1149 buf[0] = d->data[ofs+6];
1150 buf[1] = d->data[ofs+7];
1151 col2Ref = readU16( buf );
1152
1153 row1Relative = col1Ref & 0x8000;
1154 col1Relative = col1Ref & 0x4000;
1155 col1Ref &= 0x3fff;
1156
1157 row2Relative = col2Ref & 0x8000;
1158 col2Relative = col2Ref & 0x4000;
1159 col2Ref &= 0x3fff;
1160 }
1161 else
1162 {
1163 int ofs = (id() == Area) ? 0 : 14;
1164
1165 buf[0] = d->data[ofs];
1166 buf[1] = d->data[ofs+1];
1167 row1Ref = readU16( buf );
1168
1169 buf[0] = d->data[ofs+2];
1170 buf[1] = d->data[ofs+3];
1171 row2Ref = readU16( buf );
1172
1173 buf[0] = d->data[ofs+4];
1174 buf[1] = 0;
1175 col1Ref = readU16( buf );
1176
1177 buf[0] = d->data[ofs+5];
1178 buf[1] = 0;
1179 col2Ref = readU16( buf );
1180
1181 row1Relative = row2Ref & 0x8000;
1182 col1Relative = row2Ref & 0x4000;
1183 row1Ref &= 0x3fff;
1184
1185 row2Relative = row2Ref & 0x8000;
1186 col2Relative = row2Ref & 0x4000;
1187 row2Ref &= 0x3fff;
1188 }
1189
1190 UString result;
1191
1192 // not critical, just to improve performace
1193 // see also ref() function below
1194 result.reserve(40);
1195
1196 // normal use
1197 if( !col1Relative )
1198 result.append( '$' );
1199 result.append( Cell::columnLabel( col1Ref ) );
1200 if( !row1Relative )
1201 result.append( '$' );
1202 result.append( UString::number( row1Ref+1 ) );
1203 result.append( ':' );
1204 if( !col2Relative )
1205 result.append( '$' );
1206 result.append( Cell::columnLabel( col2Ref ) );
1207 if( !row2Relative )
1208 result.append( '$' );
1209 result.append( UString::number( row2Ref+1 ) );
1210
1211 return result;
1212}
1213
1214UString FormulaToken::ref( unsigned row, unsigned col ) const
1215{
1216 // sanity check
1217 if(id() != Ref)
1218 if(id() != Ref3d)
1219 return UString::null;
1220
1221 // FIXME check data size !
1222 // FIXME handle shared formula
1223 unsigned char buf[2];
1224 int rowRef, colRef;
1225 bool rowRelative, colRelative;
1226
1227 if( version() == Excel97 )
1228 {
1229 int ofs = (id() == Ref) ? 0 : 2;
1230 buf[0] = d->data[ofs];
1231 buf[1] = d->data[ofs+1];
1232 rowRef = readU16( buf );
1233
1234 buf[0] = d->data[ofs+2];
1235 buf[1] = d->data[ofs+3];
1236 colRef = readU16( buf );
1237
1238 rowRelative = colRef & 0x8000;
1239 colRelative = colRef & 0x4000;
1240 colRef &= 0x3fff;
1241 }
1242 else
1243 {
1244 int ofs = (id() == Ref) ? 0 : 14;
1245 buf[0] = d->data[ofs];
1246 buf[1] = d->data[ofs+1];
1247 rowRef = readU16( buf );
1248
1249 buf[0] = d->data[ofs+2];
1250 buf[1] = 0;
1251 colRef = readU16( buf );
1252
1253 rowRelative = rowRef & 0x8000;
1254 colRelative = rowRef & 0x4000;
1255 rowRef &= 0x3fff;
1256 }
1257
1258 UString result;
1259
1260 // not critical, just to improve performace
1261 // absolute column 4294967295, row 4294967295 is "$AATYHWUR$4294967295"
1262 // (20 characters)
1263 result.reserve(20);
1264
1265 if( !colRelative )
1266 result.append('$');
1267 result.append( Cell::columnLabel( colRef ) );
1268 if( !rowRelative )
1269 result.append('$');
1270 result.append( UString::number( rowRef+1 ) );
1271
1272 return result;
1273}
1274
1275// only when id is Ref3d or Area3d
1276unsigned FormulaToken::externSheetRef() const
1277{
1278 if(version() >= Excel97)
1279 {
1280 unsigned char buf[2];
1281 buf[0] = d->data[0];
1282 buf[1] = d->data[1];
1283 return readU16(buf);
1284 }
1285 else
1286 {
1287 unsigned char buf[2];
1288 buf[0] = d->data[0];
1289 buf[1] = d->data[1];
1290 int index = readI16(buf);
1291
1292 // negative index means own workbook
1293 if(index < 0)
1294 {
1295 // the real index (absolute value) is one-based
1296 unsigned ref = -index - 1;
1297 return ref;
1298 }
1299 }
1300
1301 return 0; // FIXME is this safe?
1302}
1303
1304// only when id is Matrix
1305unsigned FormulaToken::refRow() const
1306{
1307 // FIXME check data size !
1308 unsigned char buf[2];
1309
1310 buf[0] = d->data[0];
1311 buf[1] = d->data[1];
1312 unsigned ref = readU16(buf);
1313
1314 return ref;
1315}
1316
1317// only when id is Matrix
1318unsigned FormulaToken::refColumn() const
1319{
1320 // FIXME check data size !
1321 unsigned char buf[2];
1322
1323 buf[0] = d->data[2];
1324 buf[1] = d->data[3];
1325 unsigned ref = readU16(buf);
1326
1327 return ref;
1328}
1329
1330
1331std::ostream& Swinder::operator<<( std::ostream& s, Swinder::FormulaToken token )
1332{
1333 s << std::setw(2) << std::hex << token.id() << std::dec;
1334 // s << " Size: " << std::dec << token.size();
1335 s << " ";
1336
1337 switch( token.id() )
1338 {
1339 case FormulaToken::ErrorCode:
1340 case FormulaToken::Bool:
1341 case FormulaToken::Integer:
1342 case FormulaToken::Float:
1343 case FormulaToken::String:
1344 {
1345 Value v = token.value();
1346 s << v;
1347 }
1348 break;
1349
1350 case FormulaToken::Function:
1351 s << "Function " << token.functionName();
1352 break;
1353
1354 default:
1355 s << token.idAsString();
1356 break;
1357 }
1358
1359 return s;
1360}
1361
1362//=============================================
1363// CellInfo
1364//=============================================
1365
1366class CellInfo::Private
1367{
1368public:
1369 unsigned row;
1370 unsigned column;
1371 unsigned xfIndex;
1372};
1373
1375{
1376 info = new CellInfo::Private();
1377 info->row = 0;
1378 info->column = 0;
1379 info->xfIndex = 0;
1380}
1381
1383{
1384 delete info;
1385}
1386
1387unsigned CellInfo::row() const
1388{
1389 return info->row;
1390}
1391
1392void CellInfo::setRow( unsigned r )
1393{
1394 info->row = r;
1395}
1396
1397unsigned CellInfo::column() const
1398{
1399 return info->column;
1400}
1401
1402void CellInfo::setColumn( unsigned c )
1403{
1404 info->column = c;
1405}
1406
1407unsigned CellInfo::xfIndex() const
1408{
1409 return info->xfIndex;
1410}
1411
1412void CellInfo::setXfIndex( unsigned i )
1413{
1414 info->xfIndex = i;
1415}
1416
1417//=============================================
1418// ColumnSpanInfo
1419//=============================================
1420
1421class ColumnSpanInfo::Private
1422{
1423public:
1424 unsigned firstColumn;
1425 unsigned lastColumn;
1426};
1427
1429{
1430 spaninfo = new ColumnSpanInfo::Private();
1431 spaninfo->firstColumn = 0;
1432 spaninfo->lastColumn = 0;
1433}
1434
1436{
1437 delete spaninfo;
1438}
1439
1441{
1442 return spaninfo->firstColumn;
1443}
1444
1446{
1447 spaninfo->firstColumn = c;
1448}
1449
1451{
1452 return spaninfo->lastColumn;
1453}
1454
1456{
1457 spaninfo->lastColumn = c;
1458}
1459
1460// ========== base record ==========
1461
1462const unsigned int Record::id = 0; // invalid of-course
1463
1465{
1466 stream_position = 0;
1467 ver = Excel97;
1468}
1469
1471{
1472}
1473
1474Record* Record::create( unsigned type )
1475{
1476 Record* record = 0;
1477
1478 if( type == BOFRecord::id )
1479 record = new BOFRecord();
1480
1481 else if( type == EOFRecord::id )
1482 record = new EOFRecord();
1483
1484 if( type == BackupRecord::id )
1485 record = new BackupRecord();
1486
1487 if( type == BlankRecord::id )
1488 record = new BlankRecord();
1489
1490 if( type == BoolErrRecord::id )
1491 record = new BoolErrRecord();
1492
1493 if( type == BottomMarginRecord::id )
1494 record = new BottomMarginRecord();
1495
1496 if( type == BoundSheetRecord::id )
1497 record = new BoundSheetRecord();
1498
1499 if( type == CalcModeRecord::id )
1500 record = new CalcModeRecord();
1501
1502 if( type == ColInfoRecord::id )
1503 record = new ColInfoRecord();
1504
1505 if( type == DateModeRecord::id )
1506 record = new DateModeRecord();
1507
1508 if( type == DimensionRecord::id )
1509 record = new DimensionRecord();
1510
1511 if( type == ExternNameRecord::id )
1512 record = new ExternNameRecord();
1513
1514 if( type == ExternSheetRecord::id )
1515 record = new ExternSheetRecord();
1516
1517 else if( type == FilepassRecord::id )
1518 record = new FilepassRecord();
1519
1520 else if( type == FontRecord::id )
1521 record = new FontRecord();
1522
1523 else if( type == FooterRecord::id )
1524 record = new FooterRecord();
1525
1526 else if( type == FormatRecord::id )
1527 record = new FormatRecord();
1528
1529 else if( type == FormulaRecord::id )
1530 record = new FormulaRecord();
1531
1532 else if( type == FormulaRecord::idOld )
1533 record = new FormulaRecord();
1534
1535 else if( type == HeaderRecord::id )
1536 record = new HeaderRecord();
1537
1538 else if( type == LabelRecord::id )
1539 record = new LabelRecord();
1540
1541 else if( type == LabelSSTRecord::id )
1542 record = new LabelSSTRecord();
1543
1544 if( type == LeftMarginRecord::id )
1545 record = new LeftMarginRecord();
1546
1547 else if( type == MergedCellsRecord::id )
1548 record = new MergedCellsRecord();
1549
1550 else if( type == MulBlankRecord::id )
1551 record = new MulBlankRecord();
1552
1553 else if( type == MulRKRecord::id )
1554 record = new MulRKRecord();
1555
1556 if( type == NameRecord::id )
1557 record = new NameRecord();
1558
1559 else if( type == NumberRecord::id )
1560 record = new NumberRecord();
1561
1562 else if( type == PaletteRecord::id )
1563 record = new PaletteRecord();
1564
1565 if( type == RightMarginRecord::id )
1566 record = new RightMarginRecord();
1567
1568 else if( type == RKRecord::id )
1569 record = new RKRecord();
1570
1571 else if( type == RowRecord::id )
1572 record = new RowRecord();
1573
1574 else if( type == RStringRecord::id )
1575 record = new RStringRecord();
1576
1577 else if( type == SSTRecord::id )
1578 record = new SSTRecord();
1579
1580 else if( type == StringRecord::id )
1581 record = new StringRecord();
1582
1583 else if( type == SupbookRecord::id )
1584 record = new SupbookRecord();
1585
1586 else if( type == XFRecord::id )
1587 record = new XFRecord();
1588
1589 else if( type == TopMarginRecord::id )
1590 record = new TopMarginRecord();
1591
1592 return record;
1593}
1594
1595void Record::setPosition( unsigned pos )
1596{
1597 stream_position = pos;
1598}
1599
1600unsigned Record::position() const
1601{
1602 return stream_position;
1603}
1604
1605void Record::setData( unsigned, const unsigned char* )
1606{
1607}
1608
1609void Record::dump( std::ostream& ) const
1610{
1611 // nothing to dump
1612}
1613
1614// ========== BACKUP ==========
1615
1616const unsigned int BackupRecord::id = 0x0040;
1617
1618class BackupRecord::Private
1619{
1620public:
1621 bool backup;
1622};
1623
1625 Record()
1626{
1627 d = new BackupRecord::Private();
1628 d->backup = false;
1629}
1630
1632{
1633 delete d;
1634}
1635
1637{
1638 return d->backup;
1639}
1640
1642{
1643 d->backup = b;
1644}
1645
1646void BackupRecord::setData( unsigned size, const unsigned char* data )
1647{
1648 if( size < 2 ) return;
1649
1650 unsigned flag = readU16( data );
1651 d->backup = flag != 0;
1652}
1653
1654void BackupRecord::dump( std::ostream& out ) const
1655{
1656 out << "BACKUP" << std::endl;
1657 out << " Backup on save : " << (backup() ? "Yes" : "No") << std::endl;
1658}
1659
1660// ========== BLANK ==========
1661
1662const unsigned int BlankRecord::id = 0x0201;
1663
1668
1669void BlankRecord::setData( unsigned size, const unsigned char* data )
1670{
1671 if( size < 6 ) return;
1672
1673 setRow( readU16( data ) );
1674 setColumn( readU16( data+2 ) );
1675 setXfIndex( readU16( data+4 ) );
1676}
1677
1678void BlankRecord::dump( std::ostream& out ) const
1679{
1680 out << "BLANK" << std::endl;
1681 out << " Row : " << row() << std::endl;
1682 out << " Column : " << column() << std::endl;
1683 out << " XF Index : " << xfIndex() << std::endl;
1684}
1685
1686
1687// ========== BOF ==========
1688
1689const unsigned int BOFRecord::id = 0x0809;
1690
1691// helper class for BOFRecord
1692class BOFRecord::Private
1693{
1694public:
1695 unsigned version; // 0x0500=Excel95, 0x0600=Excel97, and so on
1696 unsigned type;
1697 unsigned build;
1698 unsigned year;
1699 unsigned history;
1700 unsigned rversion;
1701};
1702
1703// constructor of BOFRecord
1705 Record()
1706{
1707 d = new BOFRecord::Private();
1708 d->version = 0x600; // BIFF8;
1709 d->type = 0;
1710 d->build = 0;
1711 d->year = 0;
1712 d->history = 0;
1713 d->rversion = 0;
1714}
1715
1716// destructor of BOFRecord
1718{
1719 delete d;
1720}
1721
1722void BOFRecord::setData( unsigned size, const unsigned char* data )
1723{
1724 if( size < 4 ) return;
1725
1726 d->version = readU16( data );
1727 d->type = readU16( data+2 );
1728 if( size > 6 )
1729 {
1730 d->build = readU16( data+4 );
1731 d->year = readU16( data+6);
1732 if( size > 12 )
1733 {
1734 d->history = readU32( data+8 );
1735 d->rversion = readU32( data+12 );
1736 }
1737 }
1738}
1739
1740unsigned BOFRecord::version() const
1741{
1742 unsigned ver = UnknownExcel;
1743 switch( d->version )
1744 {
1745 case 0x0500 : ver = Excel95; break;
1746 case 0x0600 : ver = Excel97; break;
1747 default: break;
1748 }
1749 return ver;
1750}
1751
1753{
1754 const char *result = "Unknown";
1755 switch( version() )
1756 {
1757 case Excel95 : result = "Excel95"; break;
1758 case Excel97 : result = "Excel97"; break;
1759 default: break;
1760 }
1761 return result;
1762}
1763
1764unsigned BOFRecord::type() const
1765{
1766 unsigned result = UnknownType;
1767 switch( d->type )
1768 {
1769 case 0x005 : result = Workbook; break;
1770 case 0x006 : result = VBModule; break;
1771 case 0x010 : result = Worksheet; break;
1772 case 0x020 : result = Chart; break;
1773 case 0x040 : result = MacroSheet; break;
1774 case 0x100 : result = Workspace; break;
1775 default: break;
1776 }
1777 return result;
1778}
1779
1780const char* BOFRecord::typeAsString() const
1781{
1782 const char *result = "Unknown";
1783 switch( type() )
1784 {
1785 case Workbook : result = "Workbook"; break;
1786 case VBModule : result = "Visual Basic Module"; break;
1787 case Worksheet : result = "Worksheet"; break;
1788 case Chart : result = "Chart"; break;
1789 case MacroSheet : result = "Macro Sheet"; break;
1790 case Workspace : result = "Workspace File"; break;
1791 default: break;
1792 }
1793 return result;
1794}
1795
1796void BOFRecord::dump( std::ostream& out ) const
1797{
1798 out << "BOF" << std::endl;
1799 out << " Version : 0x" << std::hex << d->version << " (" << versionAsString() << ")" << std::endl;
1800 out << " Type : 0x" << d->type << " (" << typeAsString() << ")" << std::endl;
1801 out << " Build : 0x" << d->build << std::endl;
1802 out << " Year : " << std::dec << d->year << std::endl;
1803 out << " History : 0x" << std::hex << d->history << std::endl;
1804 out << " RVersion : 0x" << d->rversion << std::endl;
1805 out << std::dec;
1806}
1807
1808// ========== BOOLERR ==========
1809
1810const unsigned int BoolErrRecord::id = 0x0205;
1811
1812class BoolErrRecord::Private
1813{
1814public:
1815 Value value;
1816};
1817
1819 Record(), CellInfo()
1820{
1821 d = new BoolErrRecord::Private();
1822 d->value = Value( false );
1823}
1824
1826{
1827 delete d;
1828}
1829
1830void BoolErrRecord::setData( unsigned size, const unsigned char* data )
1831{
1832 if( size != 8 ) return;
1833
1834 setRow( readU16( data ) );
1835 setColumn( readU16( data+2 ) );
1836 setXfIndex( readU16( data+4 ) );
1837
1838 switch( data[7] )
1839 {
1840 case 0 :
1841 d->value = Value( data[6] ? true : false );
1842 break;
1843 case 1 :
1844 d->value = errorAsValue( data[6] );
1845 break;
1846 default:
1847 // bad bad bad
1848 std::cerr << "Warning: bad BOOLERR record" << std::endl;
1849 break;
1850 }
1851}
1852
1854{
1855 return d->value;
1856}
1857
1858void BoolErrRecord::dump( std::ostream& out ) const
1859{
1860 out << "BOOLERR" << std::endl;
1861 out << " Column : " << column() << std::endl;
1862 out << " Row : " << row() << std::endl;
1863 out << " XFIndex : " << xfIndex() << std::endl;
1864 out << " Value : " << value() << std::endl;
1865}
1866
1867// ========== BOTTOMMARGIN ==========
1868
1869const unsigned int BottomMarginRecord::id = 0x0029;
1870
1871class BottomMarginRecord::Private
1872{
1873public:
1874 double bottomMargin;
1875};
1876
1878 Record()
1879{
1880 d = new BottomMarginRecord::Private();
1881 d->bottomMargin = 1.0;
1882}
1883
1885{
1886 delete d;
1887}
1888
1890{
1891 return d->bottomMargin;
1892}
1893
1895{
1896 d->bottomMargin = m;
1897}
1898
1899void BottomMarginRecord::setData( unsigned size, const unsigned char* data )
1900{
1901 if( size < 8 ) return;
1902 setBottomMargin( readFloat64( data ) );
1903}
1904
1905void BottomMarginRecord::dump( std::ostream& out ) const
1906{
1907 out << "BOTTOMMARGIN" << std::endl;
1908 out << " Bottom Margin : " << bottomMargin() << " inches" << std::endl;
1909}
1910
1911
1912// ========== BOUNDSHEET ==========
1913
1914const unsigned int BoundSheetRecord::id = 0x0085;
1915
1916// helper class for BoundSheetRecord
1917class BoundSheetRecord::Private
1918{
1919public:
1920 unsigned type; // 0=Worksheet, 2=Chart, 6=VB Module
1921 unsigned visibility; // 0=visible, 1=hidden, 2=strong hidden
1922 UString name;
1923 unsigned bofPosition;
1924};
1925
1927 Record()
1928{
1929 d = new BoundSheetRecord::Private();
1930 d->type = 0;
1931 d->visibility = 0;
1932 d->name = "Sheet";
1933}
1934
1936{
1937 switch( t )
1938 {
1939 case Worksheet: d->type = 0; break;
1940 case Chart: d->type = 2; break;
1941 case VBModule: d->type = 6; break;
1942 default: d->type = 0; break; // fallback
1943 };
1944}
1945
1947{
1948 unsigned t = Worksheet;
1949 switch( d->type )
1950 {
1951 case 0: t = Worksheet; break;
1952 case 2: t = Chart; break;
1953 case 6: t = VBModule; break;
1954 default: break;
1955 };
1956 return t;
1957}
1958
1960{
1961 const char *result = "Unknown";
1962 switch( type() )
1963 {
1964 case Worksheet: result = "Worksheet"; break;
1965 case Chart: result = "Chart"; break;
1966 case VBModule: result = "Visual Basic Module"; break;
1967 default: break;
1968 }
1969 return result;
1970}
1971
1973{
1974 d->visibility = v ? 0 : 1;
1975}
1976
1978{
1979 return d->visibility == 0;
1980}
1981
1983{
1984 d->name = n;
1985}
1986
1988{
1989 return d->name;
1990}
1991
1993{
1994 d->bofPosition = pos;
1995}
1996
1998{
1999 return d->bofPosition;
2000}
2001
2003{
2004 delete d;
2005}
2006
2007void BoundSheetRecord::setData( unsigned size, const unsigned char* data )
2008{
2009 if( size < 6 ) return;
2010
2011 d->bofPosition = readU32( data );
2012 d->visibility = data[4];
2013 d->type = data[5];
2014
2015 /* FIXME: it turned out that sheet name is not normal unicode string
2016 where the first two bytes specifies string length, but instead
2017 only the first specifies it.
2018 the next byte could be correctly interpreted as flag.
2019 */
2020
2021 UString name = ( version() >= Excel97 ) ?
2022 EString::fromSheetName( data+6, size-6 ).str() :
2023 EString::fromByteString( data+6, false, size-6 ).str();
2024 setSheetName( name );
2025}
2026
2027void BoundSheetRecord::dump( std::ostream& out ) const
2028{
2029 out << "BOUNDSHEET" << std::endl;
2030 out << " Name : " << d->name << std::endl;
2031 out << " Type : " << d->type << " (" << typeAsString() << ")" << std::endl;
2032 out << " Visibility : " << d->visibility << " (";
2033 if( visible() ) out << "Visible"; else out << "Hidden"; out << ")" << std::endl;
2034 out << " BOF pos : " << d->bofPosition << std::endl;
2035}
2036
2037// ========== CALCMODE ==========
2038
2039const unsigned int CalcModeRecord::id = 0x000d;
2040
2041class CalcModeRecord::Private
2042{
2043public:
2044 bool autoCalc;
2045};
2046
2048 Record()
2049{
2050 d = new CalcModeRecord::Private();
2051 d->autoCalc = false;
2052}
2053
2055{
2056 delete d;
2057}
2058
2060{
2061 return d->autoCalc;
2062}
2063
2065{
2066 d->autoCalc = b;
2067}
2068
2069void CalcModeRecord::setData( unsigned size, const unsigned char* data )
2070{
2071 if( size < 2 ) return;
2072
2073 unsigned flag = readU16( data );
2074 d->autoCalc = flag != 0;
2075}
2076
2077void CalcModeRecord::dump( std::ostream& out ) const
2078{
2079 out << "CALCMODE" << std::endl;
2080 out << " Auto Calc : " << (autoCalc() ? "Yes" : "No") << std::endl;
2081}
2082
2083// ========== COLINFO ==========
2084
2085const unsigned int ColInfoRecord::id = 0x007d;
2086
2087class ColInfoRecord::Private
2088{
2089public:
2090 unsigned width;
2091 unsigned xfIndex;
2092 bool hidden;
2093 bool collapsed;
2094 unsigned outlineLevel;
2095};
2096
2099{
2100 d = new ColInfoRecord::Private();
2101 d->width = 2340;
2102 d->xfIndex = 0;
2103 d->hidden = false;
2104 d->collapsed = false;
2105 d->outlineLevel = 0;
2106}
2107
2109{
2110 delete d;
2111}
2112
2113// FIXME how to find the real width (in pt/mm/inch) ?
2114unsigned ColInfoRecord::width() const
2115{
2116 return d->width;
2117}
2118
2119void ColInfoRecord::setWidth( unsigned w )
2120{
2121 d->width = w;
2122}
2123
2125{
2126 return d->xfIndex;
2127}
2128
2130{
2131 d->xfIndex = i;
2132}
2133
2135{
2136 return d->hidden;
2137}
2138
2140{
2141 d->hidden = h;
2142}
2143
2145{
2146 return d->collapsed;
2147}
2148
2150{
2151 d->collapsed = c;
2152}
2153
2155{
2156 return d->outlineLevel;
2157}
2158
2160{
2161 d->outlineLevel = l;
2162}
2163
2164void ColInfoRecord::setData( unsigned size, const unsigned char* data )
2165{
2166 if( size < 10 ) return;
2167
2168 setFirstColumn( readU16( data ) );
2169 setLastColumn( readU16( data+2 ) );
2170 setWidth( readU16( data+4 ) );
2171 setXfIndex( readU16( data+6 ) );
2172
2173 unsigned options = readU16( data+8 );
2174 setHidden ( options & 1 );
2175 setCollapsed ( options & 0x1000 );
2176 setOutlineLevel( ( options >> 8 ) & 7 );
2177}
2178
2179void ColInfoRecord::dump( std::ostream& out ) const
2180{
2181 out << "COLINFO" << std::endl;
2182 out << " First Column : " << firstColumn() << std::endl;
2183 out << " Last Column : " << lastColumn() << std::endl;
2184 out << " Width : " << width() << std::endl;
2185 out << " XF Index : " << xfIndex() << std::endl;
2186 out << " Hidden : " << ( hidden() ? "Yes" : "No" ) << std::endl;
2187 out << " Collapsed : " << ( collapsed() ? "Yes" : "No" ) << std::endl;
2188 out << " Outline Level : " << outlineLevel() << std::endl;
2189}
2190
2191// ========== DATEMODE ==========
2192
2193const unsigned int DateModeRecord::id = 0x0022;
2194
2195class DateModeRecord::Private
2196{
2197public:
2198 bool base1904;
2199};
2200
2202 Record()
2203{
2204 d = new DateModeRecord::Private();
2205 d->base1904 = false;
2206}
2207
2209{
2210 delete d;
2211}
2212
2214{
2215 return d->base1904;
2216}
2217
2219{
2220 d->base1904 = r;
2221}
2222
2223void DateModeRecord::setData( unsigned size, const unsigned char* data )
2224{
2225 if( size < 2 ) return;
2226
2227 unsigned flag = readU16( data );
2228 d->base1904 = flag != 0;
2229}
2230
2231void DateModeRecord::dump( std::ostream& out ) const
2232{
2233 out << "DATEMODE" << std::endl;
2234 out << " 1904 base : " << (base1904() ? "Yes" : "No") << std::endl;
2235}
2236
2237
2238// ========== DIMENSION ==========
2239
2240const unsigned int DimensionRecord::id = 0x0200;
2241
2242class DimensionRecord::Private
2243{
2244public:
2245 unsigned firstRow;
2246 unsigned lastRow;
2247 unsigned firstColumn;
2248 unsigned lastColumn;
2249};
2250
2252 Record()
2253{
2254 d = new DimensionRecord::Private;
2255 d->firstRow = 0;
2256 d->lastRow = 0;
2257 d->firstColumn = 0;
2258 d->lastColumn = 0;
2259}
2260
2262{
2263 delete d;
2264}
2265
2267{
2268 return d->firstRow;
2269}
2270
2272{
2273 d->firstRow = r;
2274}
2275
2277{
2278 return d->lastRow;
2279}
2280
2282{
2283 d->lastRow = r;
2284}
2285
2287{
2288 return d->firstColumn;
2289}
2290
2292{
2293 d->firstColumn = r;
2294}
2295
2297{
2298 return d->lastColumn;
2299}
2300
2302{
2303 d->lastColumn = r;
2304}
2305
2306void DimensionRecord::setData( unsigned size, const unsigned char* data )
2307{
2308 if( size < 14 ) return;
2309
2310 setFirstRow( readU32( data ) );
2311 setLastRow( readU32( data+4 ) - 1 );
2312 setFirstColumn( readU16( data + 8 ) );
2313 setLastColumn( readU16( data + 10 ) - 1 );
2314}
2315
2316void DimensionRecord::dump( std::ostream& out ) const
2317{
2318 out << "DIMENSION" << std::endl;
2319 out << " First Row : " << firstRow() << std::endl;
2320 out << " Last Row : " << lastRow() << std::endl;
2321 out << " First Column : " << firstColumn() << std::endl;
2322 out << " Last Column : " << lastColumn() << std::endl;
2323}
2324
2325// ========== EOF ==========
2326
2327const unsigned int EOFRecord::id = 0x000a;
2328
2330 Record()
2331{
2332}
2333
2337
2338void EOFRecord::setData( unsigned, const unsigned char* )
2339{
2340 // no data associated with EOF record
2341}
2342
2343void EOFRecord::dump( std::ostream& out ) const
2344{
2345 out << "EOF" << std::endl;
2346}
2347
2348// ========== EXTERNNAME ==========
2349
2350const unsigned int ExternNameRecord::id = 0x0023;
2351
2352class ExternNameRecord::Private
2353{
2354public:
2355 unsigned optionFlags;
2356 unsigned sheetIndex; // one-based, not zero-based
2357 UString externName;
2358};
2359
2360
2361ExternNameRecord::ExternNameRecord()
2362{
2363 d = new Private;
2364 d->optionFlags = 0;
2365 d->sheetIndex = 0;
2366}
2367
2368ExternNameRecord::~ExternNameRecord()
2369{
2370 delete d;
2371}
2372
2373void ExternNameRecord::setSheetIndex( unsigned sheetIndex )
2374{
2375 d->sheetIndex = sheetIndex;
2376}
2377
2378unsigned ExternNameRecord::sheetIndex() const
2379{
2380 return d->sheetIndex;
2381}
2382
2383void ExternNameRecord::setExternName( const UString& name )
2384{
2385 d->externName = name;
2386}
2387
2388UString ExternNameRecord::externName() const
2389{
2390 return d->externName;
2391}
2392
2393void ExternNameRecord::setData( unsigned size, const unsigned char* data )
2394{
2395 if( size < 6 ) return;
2396
2397 if ( version() == Excel97 )
2398 {
2399 d->optionFlags = readU16( data );
2400 d->sheetIndex = readU16( data+2 );
2401 d->externName = EString::fromUnicodeString( data+6, false, size ).str();
2402 }
2403
2404 if ( version() == Excel95 )
2405 {
2406 d->optionFlags = 0;
2407 d->sheetIndex = 0;
2408 d->externName = EString::fromByteString( data+6, false, size ).str();
2409 }
2410}
2411
2412void ExternNameRecord::dump( std::ostream& out ) const
2413{
2414}
2415
2416// ========== EXTERNSHEET ==========
2417
2418const unsigned int ExternSheetRecord::id = 0x0017;
2419
2420class ExternSheetRecord::Private
2421{
2422public:
2423 typedef struct
2424 {
2425 unsigned index;
2426 unsigned first;
2427 unsigned last ;
2428 } ExternSheetRef;
2429 std::vector<ExternSheetRef> refs;
2430 UString refName;
2431};
2432
2433ExternSheetRecord::ExternSheetRecord()
2434{
2435 d = new Private;
2436}
2437
2438ExternSheetRecord::~ExternSheetRecord()
2439{
2440 delete d;
2441}
2442
2443unsigned ExternSheetRecord::count() const
2444{
2445 return d->refs.size();
2446}
2447
2448unsigned ExternSheetRecord::refIndex(unsigned i) const
2449{
2450 if(i >= d->refs.size()) return 0;
2451 return d->refs[i].index;
2452}
2453
2454unsigned ExternSheetRecord::firstSheet(unsigned i) const
2455{
2456 if(i >= d->refs.size()) return 0;
2457 return d->refs[i].first;
2458}
2459
2460unsigned ExternSheetRecord::lastSheet(unsigned i) const
2461{
2462 if(i >= d->refs.size()) return 0;
2463 return d->refs[i].last;
2464}
2465
2466UString ExternSheetRecord::refName() const
2467{
2468 return d->refName;
2469}
2470
2471void ExternSheetRecord::setData( unsigned size, const unsigned char* data )
2472{
2473 d->refs.clear();
2474 d->refName = UString::null;
2475
2476 // sanity
2477 if(size < 2) return;
2478
2479 if(version() >= Excel97)
2480 {
2481 // don't really trust this
2482 unsigned c = readU16(data);
2483
2484 unsigned ofs = 2;
2485 for(unsigned i = 0; i < c; i++, ofs+=6)
2486 {
2487 // sanity check
2488 if(ofs + 6 > size) break;
2489
2490 ExternSheetRecord::Private::ExternSheetRef ref;
2491 ref.index = readU16(data+ofs);
2492 ref.first = readU16(data+ofs+2);
2493 ref.last = readU16(data+ofs+4);
2494
2495 d->refs.push_back(ref);
2496 }
2497 }
2498 else
2499 {
2500 unsigned char dtype = data[1];
2501 unsigned dlen = (unsigned) data[0];
2502
2503 if(dtype == 3)
2504 {
2505 UString url;
2506 url.reserve(dlen);
2507 for(int i = 0; i < dlen; i++)
2508 {
2509 if(i + 2 > size) break;
2510 char ch = data[i + 2];
2511 if(ch >= 32)
2512 url.append(ch);
2513 }
2514 d->refName = url;
2515 }
2516 }
2517}
2518
2519void ExternSheetRecord::dump( std::ostream& out ) const
2520{
2521 out << "EXTERNSHEET" << std::endl;
2522}
2523
2524// ========== FILEPASS ==========
2525
2526const unsigned int FilepassRecord::id = 0x002f;
2527
2528FilepassRecord::FilepassRecord():
2529 Record()
2530{
2531}
2532
2533FilepassRecord::~FilepassRecord()
2534{
2535}
2536
2537void FilepassRecord::setData( unsigned, const unsigned char* )
2538{
2539 // TODO
2540}
2541
2542void FilepassRecord::dump( std::ostream& out ) const
2543{
2544 out << "FILEPASS" << std::endl;
2545}
2546
2547// ========== FONT ==========
2548
2549const unsigned int FontRecord::id = 0x0031;
2550
2551class FontRecord::Private
2552{
2553public:
2554 unsigned height;
2555 UString fontName;
2556 unsigned fontFamily;
2557 unsigned characterSet;
2558 unsigned colorIndex;
2559 unsigned boldness;
2560 bool italic;
2561 bool strikeout;
2562 unsigned escapement;
2563 unsigned underline;
2564};
2565
2567{
2568 d = new FontRecord::Private;
2569 d->height = 11;
2570 d->fontName = "Arial";
2571 d->fontFamily = 0;
2572 d->characterSet = 0;
2573 d->colorIndex = 0;
2574 d->boldness = 400;
2575 d->italic = false;
2576 d->strikeout = false;
2577 d->escapement = Normal;
2578 d->underline = None;
2579}
2580
2582{
2583 delete d;
2584}
2585
2587{
2588 d = new FontRecord::Private;
2589 operator=( ef );
2590}
2591
2593{
2594 d->height = ef.height();
2595 d->fontName = ef.fontName();
2596 d->fontFamily = ef.fontFamily();
2597 d->characterSet = ef.characterSet();
2598 d->boldness = ef.boldness();
2599 d->italic = ef.italic();
2600 d->strikeout = ef.strikeout();
2601 d->escapement = ef.escapement();
2602 d->underline = ef.underline();
2603 d->colorIndex = ef.colorIndex();
2604 return *this;
2605}
2606
2607unsigned FontRecord::height() const
2608{
2609 return d->height;
2610}
2611
2612void FontRecord::setHeight( unsigned h )
2613{
2614 d->height = h;
2615}
2616
2618{
2619 return d->fontName;
2620}
2621
2623{
2624 d->fontName = fn;
2625}
2626
2627unsigned FontRecord::fontFamily() const
2628{
2629 return d->fontFamily;
2630}
2631
2632void FontRecord::setFontFamily( unsigned f )
2633{
2634 d->fontFamily = f;
2635}
2636
2637unsigned FontRecord::characterSet() const
2638{
2639 return d->characterSet;
2640}
2641
2642void FontRecord::setCharacterSet( unsigned cs )
2643{
2644 d->characterSet = cs;
2645}
2646
2648{
2649 return d->colorIndex;
2650}
2651
2652void FontRecord::setColorIndex( unsigned ci )
2653{
2654 d->colorIndex = ci;
2655}
2656
2657unsigned FontRecord::boldness() const
2658{
2659 return d->boldness;
2660}
2661
2662void FontRecord::setBoldness( unsigned b )
2663{
2664 d->boldness = b;
2665}
2666
2668{
2669 return d->italic;
2670}
2671
2673{
2674 d->italic = i;
2675}
2676
2678{
2679 return d->strikeout;
2680}
2681
2683{
2684 d->strikeout = s;
2685}
2686
2688{
2689 return d->escapement;
2690}
2691
2693{
2694 d->escapement = s;
2695}
2696
2698{
2699 return d->underline;
2700}
2701
2703{
2704 d->underline = u;
2705}
2706
2707
2708void FontRecord::setData( unsigned size, const unsigned char* data )
2709{
2710 if( size < 14 ) return;
2711
2712 setHeight( readU16( data ) );
2713 unsigned flag = readU16( data+2 );
2714 setItalic( flag & 2 );
2715 setStrikeout( flag & 8 );
2716 setStrikeout( flag & 8 );
2717
2718 setColorIndex( readU16( data+4 ) );
2719
2720 setBoldness( readU16( data+6 ) );
2721 setEscapement( readU16( data+8 ) );
2722 setUnderline( data[10] );
2723
2724 setFontFamily( data[11] );
2725 setCharacterSet( data[12] );
2726
2727 UString fn = ( version() >= Excel97 ) ?
2728 EString::fromSheetName( data+14, size-14 ).str() :
2729 EString::fromByteString( data+14, false, size-14 ).str();
2730 setFontName( fn );
2731}
2732
2733
2734void FontRecord::dump( std::ostream& out ) const
2735{
2736 out << "FONT" << std::endl;
2737 out << " Height : " << height() << " twips" << std::endl;
2738 out << " Font Name : " << fontName() << std::endl;
2739 out << " Color Index : " << colorIndex() << std::endl;
2740 out << " Boldness : " << boldness() << std::endl;
2741 out << " Italic : " << (italic()?"Yes":"No") << std::endl;
2742 out << " Strikeout : " << (strikeout()?"Yes":"No") << std::endl;
2743 out << " Escapement : ";
2744 switch( escapement() )
2745 {
2746 case Normal: out << "Normal" << std::endl; break;
2747 case Subscript: out << "Subscript" << std::endl; break;
2748 case Superscript: out << "Superscript" << std::endl; break;
2749 default: out << "Unkown " << escapement() << std::endl; break;
2750 };
2751}
2752
2753// ========== FOOTER ==========
2754
2755const unsigned int FooterRecord::id = 0x0015;
2756
2757class FooterRecord::Private
2758{
2759public:
2761};
2762
2764 Record()
2765{
2766 d = new FooterRecord::Private();
2767}
2768
2770{
2771 delete d;
2772}
2773
2775{
2776 return d->footer;
2777}
2778
2780{
2781 d->footer = footer;
2782}
2783
2784void FooterRecord::setData( unsigned size, const unsigned char* data )
2785{
2786 if( size < 2 ) return;
2787
2788 UString footer = ( version() >= Excel97 ) ?
2789 EString::fromUnicodeString( data, true, size ).str() :
2790 EString::fromByteString( data, false, size ).str();
2791 setFooter( footer );
2792}
2793
2794void FooterRecord::dump( std::ostream& out ) const
2795{
2796 out << "FOOTER" << std::endl;
2797 out << " Footer : " << footer() << std::endl;
2798}
2799
2800// ========== FORMAT ==========
2801
2802const unsigned int FormatRecord::id = 0x041e;
2803
2804class FormatRecord::Private
2805{
2806public:
2807 unsigned index;
2809};
2810
2812 Record()
2813{
2814 d = new FormatRecord::Private;
2815 d->index = 0;
2816}
2817
2819{
2820 delete d;
2821}
2822
2824 Record()
2825{
2826 d = new FormatRecord::Private;
2827 operator=( fr );
2828}
2829
2831{
2832 d->index = fr.index();
2833 d->formatString = fr.formatString();
2834 return *this;
2835}
2836
2837unsigned FormatRecord::index() const
2838{
2839 return d->index;
2840}
2841
2842void FormatRecord::setIndex( unsigned i )
2843{
2844 d->index = i;
2845}
2846
2848{
2849 return d->formatString;
2850}
2851
2853{
2854 d->formatString = fs;
2855}
2856
2857void FormatRecord::setData( unsigned size, const unsigned char* data )
2858{
2859 if( size < 3 ) return;
2860
2861 setIndex( readU16( data ) );
2862
2863 UString fs = ( version() >= Excel97 ) ?
2864 EString::fromUnicodeString( data+2, true, size-2 ).str() :
2865 EString::fromByteString( data+2, false, size-2 ).str();
2866 setFormatString( fs );
2867}
2868
2869void FormatRecord::dump( std::ostream& out ) const
2870{
2871 out << "FORMAT" << std::endl;
2872 out << " Index : " << index() << std::endl;
2873 out << " Format String : " << formatString() << std::endl;
2874}
2875
2876
2877// ========== FORMULA ==========
2878
2879const unsigned int FormulaRecord::id = 0x0006;
2880const unsigned int FormulaRecord::idOld = 0x0206; // BIFF3, BIFF4
2881
2882class FormulaRecord::Private
2883{
2884public:
2885 Value result;
2886 FormulaTokens tokens;
2887};
2888
2890 Record()
2891{
2892 d = new FormulaRecord::Private();
2893}
2894
2896{
2897 delete d;
2898}
2899
2901{
2902 return d->result;
2903}
2904
2906{
2907 d->result = r;
2908}
2909
2910FormulaTokens FormulaRecord::tokens() const
2911{
2912 return d->tokens;
2913}
2914
2915void FormulaRecord::setData( unsigned size, const unsigned char* data )
2916{
2917 int formula_ofs = 20;
2918
2919 // sanity check
2920 if( size < formula_ofs ) return;
2921
2922 setRow( readU16( data ) );
2923 setColumn( readU16( data+2 ) );
2924
2925 setXfIndex( readU16( data+4 ) );
2926 if( readU16( data+12 ) != 0xffff )
2927 {
2928 // Floating-point
2929 setResult( Value( readFloat64( data+6 ) ) );
2930 }
2931 else
2932 {
2933 switch( data[6] )
2934 {
2935 case 0: // string, real value in subsequent string record
2936 setResult( Value( Value::String ) );
2937 break;
2938 case 1: // boolean
2939 setResult( Value( data[8] ? true : false ) );
2940 break;
2941 case 2: // error code
2942 setResult( errorAsValue( data[8] ) );
2943 break;
2944 case 3: // empty
2946 break;
2947 default: // fallback
2949 break;
2950 };
2951 }
2952
2953 unsigned formula_len = readU16( data+formula_ofs );
2954
2955 // reconstruct all tokens
2956 d->tokens.clear();
2957 for( unsigned j = formula_ofs+2; j < size; )
2958 {
2959 unsigned ptg = data[j++];
2960 ptg = ((ptg & 0x40) ? (ptg | 0x20) : ptg) & 0x3F;
2961 FormulaToken token( ptg );
2962 token.setVersion( version() );
2963
2964 if( token.id() == FormulaToken::String )
2965 {
2966 // find bytes taken to represent the string
2967 EString estr = (version()==Excel97) ?
2968 EString::fromUnicodeString( data+j, false, formula_len ) :
2969 EString::fromByteString( data+j, false, formula_len );
2970 token.setData( estr.size(), data+j );
2971 j += estr.size();
2972 }
2973 else
2974 {
2975 // normal, fixed-size token
2976 if( token.size() > 1 )
2977 {
2978 token.setData( token.size(), data+j );
2979 j += token.size();
2980 }
2981 }
2982
2983 d->tokens.push_back( token );
2984 }
2985}
2986
2987void FormulaRecord::dump( std::ostream& out ) const
2988{
2989 out << "FORMULA" << std::endl;
2990 out << " Row : " << row() << std::endl;
2991 out << " Column : " << column() << std::endl;
2992 out << " XF Index : " << xfIndex() << std::endl;
2993 out << " Result : " << result() << std::endl;
2994
2995 FormulaTokens ts = tokens();
2996 out << " Tokens : " << ts.size() << std::endl;
2997 for( unsigned i = 0; i < ts.size(); i++ )
2998 out << " " << ts[i] << std::endl;
2999
3000}
3001
3002// ========== LABEL ==========
3003
3004const unsigned int LabelRecord::id = 0x0204;
3005
3006class LabelRecord::Private
3007{
3008public:
3009 UString label;
3010};
3011
3013 Record(), CellInfo()
3014{
3015 d = new LabelRecord::Private();
3016 d->label = UString::null;
3017}
3018
3020{
3021 delete d;
3022}
3023
3025{
3026 return d->label;
3027}
3028
3030{
3031 d->label = l;
3032}
3033
3034void LabelRecord::setData( unsigned size, const unsigned char* data )
3035{
3036 if( size < 6 ) return;
3037
3038 setRow( readU16( data ) );
3039 setColumn( readU16( data+2 ) );
3040 setXfIndex( readU16( data+4 ) );
3041
3042 UString label = ( version() >= Excel97 ) ?
3043 EString::fromUnicodeString( data+6, true, size-6 ).str() :
3044 EString::fromByteString( data+6, true, size-6 ).str();
3045 setLabel( label );
3046}
3047
3048void LabelRecord::dump( std::ostream& out ) const
3049{
3050 out << "LABEL" << std::endl;
3051 out << " Row : " << row() << std::endl;
3052 out << " Column : " << column() << std::endl;
3053 out << " XF Index : " << xfIndex() << std::endl;
3054 out << " Label : " << label() << std::endl;
3055}
3056
3057// ========== HEADER ==========
3058
3059const unsigned int HeaderRecord::id = 0x0014;
3060
3061class HeaderRecord::Private
3062{
3063public:
3065};
3066
3068 Record()
3069{
3070 d = new HeaderRecord::Private();
3071}
3072
3074{
3075 delete d;
3076}
3077
3079{
3080 return d->header;
3081}
3082
3084{
3085 d->header = header;
3086}
3087
3088void HeaderRecord::setData( unsigned size, const unsigned char* data )
3089{
3090 if( size < 2 ) return;
3091
3092 UString header = ( version() >= Excel97 ) ?
3093 EString::fromUnicodeString( data, true, size ).str() :
3094 EString::fromByteString( data, false, size ).str();
3095 setHeader( header );
3096}
3097
3098void HeaderRecord::dump( std::ostream& out ) const
3099{
3100 out << "HEADER" << std::endl;
3101 out << " Header: " << header() << std::endl;
3102}
3103
3104// ========== LABELSST ==========
3105
3106const unsigned int LabelSSTRecord::id = 0x00fd;
3107
3108class LabelSSTRecord::Private
3109{
3110public:
3111 unsigned sstIndex;
3112};
3113
3115 Record(), CellInfo()
3116{
3117 d = new LabelSSTRecord::Private();
3118 d->sstIndex = 0;
3119}
3120
3122{
3123 delete d;
3124}
3125
3127{
3128 return d->sstIndex;
3129}
3130
3131void LabelSSTRecord::setData( unsigned size, const unsigned char* data )
3132{
3133 if( size < 10 ) return;
3134
3135 setRow( readU16( data ) );
3136 setColumn( readU16( data+2 ) );
3137 setXfIndex( readU16( data+4 ) );
3138
3139 d->sstIndex = readU32( data+6 );
3140}
3141
3142void LabelSSTRecord::dump( std::ostream& out ) const
3143{
3144 out << "LABELSST" << std::endl;
3145 out << " Row : " << row() << std::endl;
3146 out << " Column : " << column() << std::endl;
3147 out << " XF Index : " << xfIndex() << std::endl;
3148 out << " SST Index : " << d->sstIndex << std::endl;
3149}
3150
3151// ========== LEFTMARGIN ==========
3152
3153const unsigned int LeftMarginRecord::id = 0x0026;
3154
3155class LeftMarginRecord::Private
3156{
3157public:
3158 double leftMargin;
3159};
3160
3162 Record()
3163{
3164 d = new LeftMarginRecord::Private();
3165 d->leftMargin = 1.0;
3166}
3167
3169{
3170 delete d;
3171}
3172
3174{
3175 return d->leftMargin;
3176}
3177
3179{
3180 d->leftMargin = m;
3181}
3182
3183void LeftMarginRecord::setData( unsigned size, const unsigned char* data )
3184{
3185 if( size < 8 ) return;
3186 setLeftMargin( readFloat64( data ) );
3187}
3188
3189void LeftMarginRecord::dump( std::ostream& out ) const
3190{
3191 out << "LEFTMARGIN" << std::endl;
3192 out << " Left Margin : " << leftMargin() << " inches" << std::endl;
3193}
3194
3195// ========== MERGEDCELLS ==========
3196
3197const unsigned int MergedCellsRecord::id = 0x00e5;
3198
3199class MergedInfo
3200{
3201public:
3202 unsigned firstRow, lastRow, firstColumn, lastColumn;
3203};
3204
3205class MergedCellsRecord::Private
3206{
3207public:
3208 std::vector<MergedInfo> mergedCells;
3209};
3210
3212 Record()
3213{
3214 d = new MergedCellsRecord::Private();
3215}
3216
3218{
3219 delete d;
3220}
3221
3223{
3224 return d->mergedCells.size();
3225}
3226
3227unsigned MergedCellsRecord::firstRow( unsigned i ) const
3228{
3229 if( i >= d->mergedCells.size() ) return 0;
3230 MergedInfo info = d->mergedCells[ i ];
3231 return info.firstRow;
3232}
3233
3234unsigned MergedCellsRecord::lastRow( unsigned i ) const
3235{
3236 if( i >= d->mergedCells.size() ) return 0;
3237 MergedInfo info = d->mergedCells[ i ];
3238 return info.lastRow;
3239}
3240
3241unsigned MergedCellsRecord::firstColumn( unsigned i ) const
3242{
3243 if( i >= d->mergedCells.size() ) return 0;
3244 MergedInfo info = d->mergedCells[ i ];
3245 return info.firstColumn;
3246}
3247
3248unsigned MergedCellsRecord::lastColumn( unsigned i ) const
3249{
3250 if( i >= d->mergedCells.size() ) return 0;
3251 MergedInfo info = d->mergedCells[ i ];
3252 return info.lastColumn;
3253}
3254
3255void MergedCellsRecord::setData( unsigned size, const unsigned char* data )
3256{
3257 if( size < 2 ) return;
3258
3259 unsigned num = readU16( data );
3260
3261 // sanity check
3262 if( size < 2 + num*4 ) return;
3263
3264 unsigned p = 2;
3265 for( unsigned i = 0; i < num; i++ )
3266 {
3267 MergedInfo info;
3268 info.firstRow = readU16( data + p );
3269 info.lastRow = readU16( data + p + 2 );
3270 info.firstColumn = readU16( data + p + 4 );
3271 info.lastColumn = readU16( data + p + 6 );
3272 p += 8;
3273 d->mergedCells.push_back( info );
3274 }
3275}
3276
3277void MergedCellsRecord::dump( std::ostream& out ) const
3278{
3279 out << "MERGEDCELLS" << std::endl;
3280 out << " Count : " << count() << std::endl;
3281 for( unsigned c = 0; c < count(); c++ )
3282 {
3283 out << " Merged Cell #" << c << " : ";
3284 out << "Column " << firstColumn(c) << "-" << lastColumn(c);
3285 out << " Row " << firstRow(c) << "-" << lastRow(c);
3286 out << std::endl;
3287 }
3288}
3289
3290// ========== MULBLANK ==========
3291
3292const unsigned int MulBlankRecord::id = 0x00be;
3293
3294class MulBlankRecord::Private
3295{
3296public:
3297 std::vector<unsigned> xfIndexes;
3298};
3299
3302{
3303 d = new MulBlankRecord::Private();
3304}
3305
3307{
3308 delete d;
3309}
3310
3311void MulBlankRecord::setData( unsigned size, const unsigned char* data )
3312{
3313 if( size < 6 ) return;
3314
3315 setRow( readU16( data ) );
3316
3317 setFirstColumn( readU16( data+2 ) );
3318 setLastColumn( readU16( data+size-2 ) );
3319
3320 d->xfIndexes.clear();
3321 for( unsigned i = 4; i < size-2; i+= 2 )
3322 d->xfIndexes.push_back( readU16( data+i ) );
3323
3324 // FIXME sentinel !
3325}
3326
3327unsigned MulBlankRecord::xfIndex( unsigned i ) const
3328{
3329 if( i >= d->xfIndexes.size() ) return 0;
3330 return d->xfIndexes[ i ];
3331}
3332
3333void MulBlankRecord::dump( std::ostream& out ) const
3334{
3335 out << "MULBLANK" << std::endl;
3336 out << " Row : " << row() << std::endl;
3337 out << " First Column : " << firstColumn() << std::endl;
3338 out << " Last Column : " << lastColumn() << std::endl;
3339}
3340
3341// ========== MULRK ==========
3342
3343const unsigned int MulRKRecord::id = 0x00bd;
3344
3345class MulRKRecord::Private
3346{
3347public:
3348 std::vector<unsigned> xfIndexes;
3349 std::vector<bool> isIntegers;
3350 std::vector<int> intValues;
3351 std::vector<double> floatValues;
3352 std::vector<unsigned> rkValues;
3353};
3354
3357{
3358 d = new MulRKRecord::Private();
3359}
3360
3362{
3363 delete d;
3364}
3365
3366unsigned MulRKRecord::xfIndex( unsigned i ) const
3367{
3368 if( i >= d->xfIndexes.size() ) return 0;
3369 return d->xfIndexes[ i ];
3370}
3371
3372bool MulRKRecord::isInteger( unsigned i ) const
3373{
3374 if( i >= d->isIntegers.size() ) return true;
3375 return d->isIntegers[ i ];
3376}
3377
3378int MulRKRecord::asInteger( unsigned i ) const
3379{
3380 if( i >= d->intValues.size() ) return 0;
3381 return d->intValues[ i ];
3382}
3383
3384double MulRKRecord::asFloat( unsigned i ) const
3385{
3386 if( i >= d->floatValues.size() ) return 0.0;
3387 return d->floatValues[ i ];
3388}
3389
3390unsigned MulRKRecord::encodedRK( unsigned i ) const
3391{
3392 if( i >= d->rkValues.size() ) return 0;
3393 return d->rkValues[ i ];
3394}
3395
3396void MulRKRecord::setData( unsigned size, const unsigned char* data )
3397{
3398 if( size < 6 ) return;
3399
3400 setRow( readU16( data ) );
3401
3402 setFirstColumn( readU16( data+2 ) );
3403 setLastColumn( readU16( data+size-2 ) );
3404
3405 d->xfIndexes.clear();
3406 d->isIntegers.clear();
3407 d->intValues.clear();
3408 d->floatValues.clear();
3409 for( unsigned i = 4; i < size-2; i+= 6 )
3410 {
3411 d->xfIndexes.push_back( readU16( data+i ) );
3412 unsigned rk = readU32( data+i+2 );
3413 d->rkValues.push_back( rk );
3414 bool isInteger = true; int iv = 0; double fv = 0.0;
3415 decodeRK( rk, isInteger, iv, fv );
3416
3417 d->isIntegers.push_back( isInteger );
3418 d->intValues.push_back( isInteger ? iv : (int)fv );
3419 d->floatValues.push_back( !isInteger ? fv : (double)iv );
3420 }
3421
3422 // FIXME sentinel !
3423}
3424
3425void MulRKRecord::dump( std::ostream& out ) const
3426{
3427 out << "MULRK" << std::endl;
3428 out << " Row : " << row() << std::endl;
3429 out << " First Column : " << firstColumn() << std::endl;
3430 out << " Last Column : " << lastColumn() << std::endl;
3431 for( unsigned c = firstColumn(); c <= lastColumn(); c++ )
3432 {
3433 out << " Column " << c << " : " << asFloat( c-firstColumn() );
3434 out << " Encoded: " << std::hex << encodedRK( c-firstColumn() );
3435 out << std::endl;
3436 }
3437}
3438
3439// ========== NAME ==========
3440
3441const unsigned int NameRecord::id = 0x0018;
3442
3443class NameRecord::Private
3444{
3445public:
3446 unsigned optionFlags;
3447 UString definedName;
3448};
3449
3450
3451NameRecord::NameRecord()
3452{
3453 d = new Private;
3454 d->optionFlags = 0;
3455}
3456
3457NameRecord::~NameRecord()
3458{
3459 delete d;
3460}
3461
3462void NameRecord::setDefinedName( const UString& name )
3463{
3464 d->definedName = name;
3465}
3466
3467UString NameRecord::definedName() const
3468{
3469 return d->definedName;
3470}
3471
3472void NameRecord::setData( unsigned size, const unsigned char* data )
3473{
3474 if( size < 14 ) return;
3475
3476 d->optionFlags = readU16( data );
3477 unsigned len = data[3];
3478
3479 if ( version() == Excel95 )
3480 {
3481 char* buffer = new char[ len+1 ];
3482 memcpy( buffer, data + 14, len );
3483 buffer[ len ] = 0;
3484 d->definedName = UString( buffer );
3485 delete[] buffer;
3486 }
3487
3488 if ( version() == Excel97 )
3489 {
3490 UString str = UString();
3491 for( unsigned k=0; k<len; k++ )
3492 {
3493 unsigned uch = readU16( data + 14 + k*2 );
3494 str.append( UChar(uch) );
3495 }
3496 d->definedName = str;
3497 }
3498}
3499
3500void NameRecord::dump( std::ostream& out ) const
3501{
3502}
3503
3504// ========== Number ==========
3505
3506const unsigned int NumberRecord::id = 0x0203;
3507
3508class NumberRecord::Private
3509{
3510public:
3511 double number;
3512};
3513
3515 Record(), CellInfo()
3516{
3517 d = new NumberRecord::Private();
3518 d->number = 0.0;
3519}
3520
3522{
3523 delete d;
3524}
3525
3527{
3528 return d->number;
3529}
3530
3532{
3533 d->number = f;
3534}
3535
3536// FIXME check that sizeof(double) is 64
3537void NumberRecord::setData( unsigned size, const unsigned char* data )
3538{
3539 if( size < 14 ) return;
3540
3541 setRow( readU16( data ) );
3542 setColumn( readU16( data+2 ) );
3543 setXfIndex( readU16( data+4 ) );
3544 setNumber( readFloat64( data+6 ) );
3545}
3546
3547void NumberRecord::dump( std::ostream& out ) const
3548{
3549 out << "NUMBER" << std::endl;
3550 out << " Row : " << row() << std::endl;
3551 out << " Column : " << column() << std::endl;
3552 out << " XF Index : " << xfIndex() << std::endl;
3553 out << " Value : " << number() << std::endl;
3554}
3555
3556// ========== PALETTE ==========
3557
3558const unsigned int PaletteRecord::id = 0x0092;
3559
3560class PaletteRecord::Private
3561{
3562public:
3563 std::vector<Color> colors;
3564};
3565
3567 Record()
3568{
3569 d = new PaletteRecord::Private();
3570}
3571
3573{
3574 delete d;
3575}
3576
3577Color PaletteRecord::color( unsigned i ) const
3578{
3579 return d->colors[ i ];
3580}
3581
3582unsigned PaletteRecord::count() const
3583{
3584 return d->colors.size();
3585}
3586
3587void PaletteRecord::setData( unsigned size, const unsigned char* data )
3588{
3589 if( size < 14 ) return;
3590
3591 unsigned num = readU16( data );
3592
3593 unsigned p = 2;
3594 for( unsigned i = 0; i < num; i++, p+=4 )
3595 {
3596 unsigned red = data[ p ];
3597 unsigned green = data[ p+1 ];
3598 unsigned blue = data[ p+2 ];
3599 d->colors.push_back( Color( red, green, blue ) );
3600 }
3601}
3602
3603void PaletteRecord::dump( std::ostream& out ) const
3604{
3605 out << "PALETTE" << std::endl;
3606 out << " Count : " << count() << std::endl;
3607 for( unsigned i = 0; i < count(); i++ )
3608 {
3609 out << " Color #" << std::setw(2) << i << " : ";
3610 Color c = color( i );
3611 out << "R:" << std::setw(3) << c.red;
3612 out << " G:" << std::setw(3) << c.green;
3613 out << " B:" << std::setw(3) << c.blue << std::endl;
3614 }
3615}
3616
3617// ========== RIGHTMARGIN ==========
3618
3619const unsigned int RightMarginRecord::id = 0x0027;
3620
3621class RightMarginRecord::Private
3622{
3623public:
3624 double rightMargin;
3625};
3626
3628 Record()
3629{
3630 d = new RightMarginRecord::Private();
3631 d->rightMargin = 1.0;
3632}
3633
3635{
3636 delete d;
3637}
3638
3640{
3641 return d->rightMargin;
3642}
3643
3645{
3646 d->rightMargin = m;
3647}
3648
3649void RightMarginRecord::setData( unsigned size, const unsigned char* data )
3650{
3651 if( size < 8 ) return;
3652 setRightMargin( readFloat64( data ) );
3653}
3654
3655void RightMarginRecord::dump( std::ostream& out ) const
3656{
3657 out << "RIGHTMARGIN" << std::endl;
3658 out << " Right Margin : " << rightMargin() << " inches " << std::endl;
3659}
3660
3661// ========== RK ==========
3662
3663const unsigned int RKRecord::id = 0x027e;
3664
3665class RKRecord::Private
3666{
3667public:
3668 bool integer;
3669 unsigned rk;
3670 int i;
3671 double f;
3672};
3673
3675 Record(), CellInfo()
3676{
3677 d = new RKRecord::Private();
3678 d->integer = true;
3679 d->rk = 0;
3680 d->i = 0;
3681 d->f = 0.0;
3682}
3683
3685{
3686 delete d;
3687}
3688
3690{
3691 return d->integer;
3692}
3693
3695{
3696 return !d->integer;
3697}
3698
3700{
3701 if( d->integer )
3702 return d->i;
3703 else
3704 return (int)d->f;
3705}
3706
3707double RKRecord::asFloat() const
3708{
3709 if( !d->integer )
3710 return d->f;
3711 else
3712 return (double)d->i;
3713}
3714
3716{
3717 d->integer = true;
3718 d->i = i;
3719 d->f = (double)i;
3720}
3721
3722void RKRecord::setFloat( double f )
3723{
3724 d->integer = false;
3725 d->i = (int)f;
3726 d->f = f;
3727}
3728
3729unsigned RKRecord::encodedRK() const
3730{
3731 return d->rk;
3732}
3733
3734// FIXME check sizeof(int) is 32
3735// big vs little endian problem
3736void RKRecord::setData( unsigned size, const unsigned char* data )
3737{
3738 if( size < 10 ) return;
3739
3740 setRow( readU16( data ) );
3741 setColumn( readU16( data+2 ) );
3742 setXfIndex( readU16( data+4 ) );
3743
3744 int i = 0; double f = 0.0;
3745 d->rk = readU32( data+6 );
3746 decodeRK( d->rk, d->integer, i, f );
3747 if( d->integer ) setInteger( i );
3748 else setFloat( f );
3749}
3750
3751void RKRecord::dump( std::ostream& out ) const
3752{
3753 out << "RK" << std::endl;
3754 out << " Row : " << row() << std::endl;
3755 out << " Column : " << column() << std::endl;
3756 out << " XF Index : " << xfIndex() << std::endl;
3757 out << " Value : " << asFloat() << std::endl;
3758 out << " Encoded RK : 0x" << std::hex << encodedRK() << std::endl;
3759 out << std::dec;
3760}
3761
3762// ========== Row ==========
3763
3764const unsigned int RowRecord::id = 0x0208;
3765
3766class RowRecord::Private
3767{
3768public:
3769 unsigned row;
3770 unsigned height;
3771 unsigned xfIndex;
3772 bool hidden;
3773};
3774
3777{
3778 d = new RowRecord::Private();
3779 d->row = 0;
3780 d->height = 50;
3781 d->xfIndex = 0;
3782 d->hidden = false;
3783}
3784
3786{
3787 delete d;
3788}
3789
3790unsigned RowRecord::row() const
3791{
3792 return d->row;
3793}
3794
3795void RowRecord::setRow( unsigned r )
3796{
3797 d->row = r;
3798}
3799
3800unsigned RowRecord::height() const
3801{
3802 return d->height;
3803}
3804
3805void RowRecord::setHeight( unsigned h )
3806{
3807 d->height = h;
3808}
3809
3810unsigned RowRecord::xfIndex() const
3811{
3812 return d->xfIndex;
3813}
3814
3815void RowRecord::setXfIndex( unsigned i )
3816{
3817 d->xfIndex = i;
3818}
3819
3821{
3822 return d->hidden;
3823}
3824
3826{
3827 d->hidden = h;
3828}
3829
3830void RowRecord::setData( unsigned size, const unsigned char* data )
3831{
3832 if( size < 16 ) return;
3833
3834 setRow( readU16( data ) );
3835 setFirstColumn( readU16( data+2 ) );
3836 setLastColumn( readU16( data+4 ) );
3837 setHeight( readU16( data+6 ) & 0x7fff );
3838 setXfIndex( readU16( data+14 ) & 0xfff );
3839
3840 unsigned options = readU16( data+12 );
3841 setHidden ( options & 0x20 );
3842}
3843
3844void RowRecord::dump( std::ostream& out ) const
3845{
3846 out << "ROW" << std::endl;
3847 out << " Row : " << row() << std::endl;
3848 out << " First Column : " << firstColumn() << std::endl;
3849 out << " Last Column : " << lastColumn() << std::endl;
3850 out << " Height : " << height() << std::endl;
3851 out << " XF Index : " << xfIndex() << std::endl;
3852 out << " Hidden : " << ( hidden() ? "Yes" : "No" ) << std::endl;
3853}
3854
3855// ========== RSTRING ==========
3856
3857const unsigned int RStringRecord::id = 0x00d6;
3858
3859class RStringRecord::Private
3860{
3861public:
3862 UString label;
3863};
3864
3866 Record(), CellInfo()
3867{
3868 d = new RStringRecord::Private();
3869 d->label = UString::null;
3870}
3871
3873{
3874 delete d;
3875}
3876
3878{
3879 return d->label;
3880}
3881
3883{
3884 d->label = l;
3885}
3886
3887// FIXME formatting runs ? in EString perhaps ?
3888void RStringRecord::setData( unsigned size, const unsigned char* data )
3889{
3890 if( size < 6 ) return;
3891
3892 setRow( readU16( data ) );
3893 setColumn( readU16( data+2 ) );
3894 setXfIndex( readU16( data+4 ) );
3895
3896 // FIXME check Excel97
3897 UString label = ( version() >= Excel97 ) ?
3898 EString::fromUnicodeString( data+6, true, size-6 ).str() :
3899 EString::fromByteString( data+6, true, size-6 ).str();
3900 setLabel( label );
3901}
3902
3903void RStringRecord::dump( std::ostream& out ) const
3904{
3905 out << "RSTRING" << std::endl;
3906 out << " Row : " << row() << std::endl;
3907 out << " Column : " << column() << std::endl;
3908 out << " XF Index : " << xfIndex() << std::endl;
3909 out << " Label : " << label() << std::endl;
3910}
3911
3912// ========== SST ==========
3913
3914const unsigned int SSTRecord::id = 0x00fc;
3915
3916class SSTRecord::Private
3917{
3918public:
3919 unsigned total;
3920 unsigned count;
3921 std::vector<UString> strings;
3922};
3923
3925 Record()
3926{
3927 d = new SSTRecord::Private();
3928 d->total = 0;
3929 d->count = 0;
3930}
3931
3933{
3934 delete d;
3935}
3936
3937UString sstrecord_get_plain_string( const unsigned char* data, unsigned length )
3938{
3939 char* buffer = new char[ length+1 ];
3940 memcpy( buffer, data, length );
3941 buffer[ length ] = 0;
3942 UString str = UString( buffer );
3943 delete[] buffer;
3944 return str;
3945}
3946
3947void SSTRecord::setData( unsigned size, const unsigned char* data )
3948{
3949 if( size < 8 ) return;
3950
3951 d->total = readU32( data );
3952 d->count = readU32( data+4 );
3953
3954 unsigned offset = 8;
3955 d->strings.clear();
3956
3957 for( unsigned i = 0; i < d->count; i++ )
3958 {
3959 // check against size
3960 if (offset >= size) {
3961 std::cerr << "Warning: reached end of SST record, but not all strings have been read!" << std::endl;
3962 break;
3963 }
3964
3965 EString es = EString::fromUnicodeString( data+offset, true, size - offset );
3966 d->strings.push_back( es.str() );
3967 offset += es.size();
3968 }
3969
3970 // safety, add null string if we can't read all of the rest
3971 while( d->strings.size() < d->count )
3972 d->strings.push_back( UString() );
3973
3974
3975 // sanity check, adjust to safer condition
3976 if( d->count < d->strings.size() )
3977 {
3978 std::cerr << "Warning: mismatch number of string in SST record!" << std::endl;
3979 d->count = d->strings.size();
3980 }
3981}
3982
3983unsigned SSTRecord::count() const
3984{
3985 return d->count;
3986}
3987
3988// why not just string() ? to avoid easy confusion with std::string
3989UString SSTRecord::stringAt( unsigned index ) const
3990{
3991 if( index >= count()) return UString::null;
3992 return d->strings[ index ];
3993}
3994
3995void SSTRecord::dump( std::ostream& out ) const
3996{
3997 out << "SST" << std::endl;
3998 out << " Occurences : " << d->total << std::endl;
3999 out << " Count : " << count() << std::endl;
4000 for( unsigned i = 0; i < count(); i++ )
4001 out << " String #" << std::setw(2) << i << " : " <<
4002 stringAt( i ) << std::endl;
4003}
4004
4005// ========== STRING ==========
4006
4007const unsigned int StringRecord::id = 0x0207;
4008
4009class StringRecord::Private
4010{
4011public:
4012 UString string;
4013};
4014
4016 Record()
4017{
4018 d = new StringRecord::Private();
4019}
4020
4022{
4023 delete d;
4024}
4025
4026void StringRecord::setData( unsigned size, const unsigned char* data )
4027{
4028 if( size < 3 ) return;
4029
4030 // TODO simple string for BIFF7
4031
4032 EString es = EString::fromUnicodeString( data, true, size );
4033 d->string = es.str();
4034}
4035
4037{
4038 return d->string;
4039}
4040
4042{
4043 return Value( d->string );
4044}
4045
4046void StringRecord::dump( std::ostream& out ) const
4047{
4048 out << "STRING" << std::endl;
4049 out << " String : " << ustring() << std::endl;
4050}
4051
4052// ========== SUPBOOK ==========
4053
4054const unsigned int SupbookRecord::id = 0x01ae;
4055
4056class SupbookRecord::Private
4057{
4058public:
4059 SupbookRecord::ReferenceType type;
4060};
4061
4063{
4064 d = new Private;
4065 d->type = UnknownRef;
4066}
4067
4069{
4070 delete d;
4071}
4072
4073SupbookRecord::ReferenceType SupbookRecord::referenceType() const
4074{
4075 return d->type;
4076}
4077
4078void SupbookRecord::setReferenceType(SupbookRecord::ReferenceType type)
4079{
4080 d->type = type;
4081}
4082
4083void SupbookRecord::setData( unsigned size, const unsigned char* data )
4084{
4085 setReferenceType(UnknownRef);
4086
4087 if( version() >= Excel97 )
4088 {
4089 // check for add-in function or internal ref first
4090 if(size == 4)
4091 {
4092 unsigned id1 = readU16(data);
4093 unsigned id2 = readU16(data+2);
4094 if((id1 == 1) && (id2 == 0x3a01))
4095 setReferenceType(AddInRef);
4096
4097 // check for internal reference
4098 if((id1 > 0) && (id2 == 0x0401))
4099 setReferenceType(InternalRef);
4100 }
4101
4102 // check for object (DDE/OLE) link
4103 if(referenceType() == UnknownRef)
4104 if(size > 2)
4105 {
4106 unsigned id1 = readU16(data);
4107 if(id1 == 0)
4108 setReferenceType(ObjectLink);
4109 }
4110
4111 // no match, must be external ref
4112 if(referenceType() == UnknownRef)
4113 setReferenceType(ExternalRef);
4114 }
4115}
4116
4117void SupbookRecord::dump( std::ostream& out ) const
4118{
4119 out << "SUPBOOK" << std::endl;
4120}
4121
4122
4123// ========== TOPMARGIN ==========
4124
4125const unsigned int TopMarginRecord::id = 0x0028;
4126
4127class TopMarginRecord::Private
4128{
4129public:
4130 double topMargin;
4131};
4132
4134 Record()
4135{
4136 d = new TopMarginRecord::Private();
4137 d->topMargin = 1.0;
4138}
4139
4141{
4142 delete d;
4143}
4144
4146{
4147 return d->topMargin;
4148}
4149
4151{
4152 d->topMargin = m;
4153}
4154
4155void TopMarginRecord::setData( unsigned size, const unsigned char* data )
4156{
4157 if( size < 8 ) return;
4158 setTopMargin( readFloat64( data ) );
4159}
4160
4161void TopMarginRecord::dump( std::ostream& out ) const
4162{
4163 out << "TOPMARGIN" << std::endl;
4164 out << " Top Margin : " << topMargin() << " inches " << std::endl;
4165}
4166
4167// ========== XF ==========
4168
4169const unsigned int XFRecord::id = 0x00e0;
4170
4171class XFRecord::Private
4172{
4173public:
4174 unsigned fontIndex;
4175 unsigned formatIndex;
4176 bool locked;
4177 bool formulaHidden;
4178 unsigned parentStyle;
4179 unsigned horizontalAlignment;
4180 unsigned verticalAlignment;
4181 bool textWrap;
4182 unsigned rotationAngle;
4183 bool stackedLetters;
4184 unsigned indentLevel;
4185 bool shrinkContent;
4186 unsigned leftBorderStyle;
4187 unsigned leftBorderColor;
4188 unsigned rightBorderStyle;
4189 unsigned rightBorderColor;
4190 unsigned topBorderStyle;
4191 unsigned topBorderColor;
4192 unsigned bottomBorderStyle;
4193 unsigned bottomBorderColor;
4194 bool diagonalTopLeft;
4195 bool diagonalBottomLeft;
4196 unsigned diagonalStyle;
4197 unsigned diagonalColor;
4198 unsigned fillPattern;
4199 unsigned patternForeColor;
4200 unsigned patternBackColor;
4201};
4202
4204{
4205 d = new XFRecord::Private();
4206 d->fontIndex = 0;
4207 d->formatIndex = 0;
4208 d->locked = false;
4209 d->formulaHidden = false;
4210 d->parentStyle = 0;
4211 d->horizontalAlignment = Left;
4212 d->verticalAlignment = VCentered;
4213 d->textWrap = false;
4214 d->rotationAngle = 0;
4215 d->stackedLetters = 0;
4216 d->indentLevel = 0;
4217 d->shrinkContent = 0;
4218 d->leftBorderStyle = 0;
4219 d->leftBorderColor = 0;
4220 d->rightBorderStyle = 0;
4221 d->rightBorderColor = 0;
4222 d->topBorderStyle = 0;
4223 d->topBorderColor = 0;
4224 d->bottomBorderStyle = 0;
4225 d->bottomBorderColor = 0;
4226 d->diagonalTopLeft = false;
4227 d->diagonalBottomLeft = false;
4228 d->diagonalStyle = 0;
4229 d->diagonalColor = 0;
4230 d->fillPattern = 0;
4231 d->patternForeColor = 0;
4232 d->patternBackColor = 0;
4233}
4234
4236{
4237 delete d;
4238}
4239
4241{
4242 d = new XFRecord::Private();
4243 operator=( xf );
4244}
4245
4247{
4248 d->fontIndex = xf.fontIndex();
4249 d->formatIndex = xf.formatIndex();
4250 d->locked = xf.locked();
4251 d->formulaHidden = xf.formulaHidden();
4252 d->parentStyle = xf.parentStyle();
4253 d->horizontalAlignment = xf.horizontalAlignment();
4254 d->verticalAlignment = xf.verticalAlignment();
4255 d->textWrap = xf.textWrap();
4256 d->rotationAngle = xf.rotationAngle();
4257 d->stackedLetters = xf.stackedLetters();
4258 d->indentLevel = xf.indentLevel();
4259 d->shrinkContent = xf.shrinkContent();
4260 d->leftBorderStyle = xf.leftBorderStyle();
4261 d->leftBorderColor = xf.leftBorderColor();
4262 d->rightBorderStyle = xf.rightBorderStyle();
4263 d->rightBorderColor = xf.rightBorderColor();
4264 d->topBorderStyle = xf.topBorderStyle();
4265 d->topBorderColor = xf.topBorderColor();
4266 d->bottomBorderStyle = xf.bottomBorderStyle();
4267 d->bottomBorderColor = xf.bottomBorderColor();
4268 d->diagonalTopLeft = xf.diagonalTopLeft();
4269 d->diagonalBottomLeft = xf.diagonalBottomLeft();
4270 d->diagonalStyle = xf.diagonalStyle();
4271 d->diagonalColor = xf.diagonalColor();
4272 d->fillPattern = xf.fillPattern();
4273 d->patternForeColor = xf.patternForeColor();
4274 d->patternBackColor = xf.patternBackColor();
4275 return *this;
4276}
4277
4278unsigned XFRecord::fontIndex() const
4279{
4280 return d->fontIndex;
4281}
4282
4283void XFRecord::setFontIndex( unsigned fi )
4284{
4285 d->fontIndex = fi;
4286}
4287
4289{
4290 return d->formatIndex;
4291}
4292
4293void XFRecord::setFormatIndex( unsigned fi )
4294{
4295 d->formatIndex = fi;
4296}
4297
4299{
4300 return d->locked;
4301}
4302
4304{
4305 d->locked = l;
4306}
4307
4309{
4310 return d->formulaHidden;
4311}
4312
4314{
4315 d->formulaHidden = f;
4316}
4317
4319{
4320 return d->parentStyle;
4321}
4322
4324{
4325 d->parentStyle = p;
4326}
4327
4329{
4330 return d->horizontalAlignment;
4331}
4332
4334{
4335 d->horizontalAlignment = ha;
4336}
4337
4339{
4340 const char *result = "Unknown";
4341 switch( horizontalAlignment() )
4342 {
4343 case General: result = "General"; break;
4344 case Left: result = "Left"; break;
4345 case Centered: result = "Centered"; break;
4346 case Right: result = "Right"; break;
4347 case Justified: result = "Justified"; break;
4348 case Filled: result = "Filled"; break;
4349 default: break;
4350 }
4351 return result;
4352}
4353
4355{
4356 return d->verticalAlignment;
4357}
4358
4360{
4361 d->verticalAlignment = va;
4362}
4363
4365{
4366 const char *result = "Unknown";
4367 switch( verticalAlignment() )
4368 {
4369 case Top: result = "Top"; break;
4370 case VCentered: result = "Centered"; break;
4371 case Bottom: result = "Bottom"; break;
4372 case VJustified: result = "Justified"; break;
4373 case VDistributed: result = "Distributed"; break;
4374 default: break;
4375 }
4376 return result;
4377}
4378
4380{
4381 return d->textWrap;
4382}
4383
4384void XFRecord::setTextWrap( bool wrap )
4385{
4386 d->textWrap = wrap;
4387}
4388
4390{
4391 return d->rotationAngle;
4392}
4393
4394void XFRecord::setRotationAngle( unsigned angle )
4395{
4396 d->rotationAngle = angle;
4397}
4398
4400{
4401 return d->stackedLetters;
4402}
4403
4405{
4406 d->stackedLetters = stacked;
4407}
4408
4410{
4411 return d->indentLevel;
4412}
4413
4415{
4416 d->indentLevel = i;
4417}
4418
4420{
4421 return d->shrinkContent;
4422}
4423
4425{
4426 d->shrinkContent = s;
4427}
4428
4430{
4431 return d->leftBorderStyle;
4432}
4433
4434void XFRecord::setLeftBorderStyle( unsigned style )
4435{
4436 d->leftBorderStyle = style;
4437}
4438
4440{
4441 return d->leftBorderColor;
4442}
4443
4444void XFRecord::setLeftBorderColor( unsigned color )
4445{
4446 d->leftBorderColor = color;
4447}
4448
4450{
4451 return d->rightBorderStyle;
4452}
4453
4454void XFRecord::setRightBorderStyle( unsigned style )
4455{
4456 d->rightBorderStyle = style;
4457}
4458
4460{
4461 return d->rightBorderColor;
4462}
4463
4464void XFRecord::setRightBorderColor( unsigned color )
4465{
4466 d->rightBorderColor = color;
4467}
4468
4470{
4471 return d->topBorderStyle;
4472}
4473
4474void XFRecord::setTopBorderStyle( unsigned style )
4475{
4476 d->topBorderStyle = style;
4477}
4478
4480{
4481 return d->topBorderColor;
4482}
4483
4484void XFRecord::setTopBorderColor( unsigned color )
4485{
4486 d->topBorderColor = color;
4487}
4488
4490{
4491 return d->bottomBorderStyle;
4492}
4493
4495{
4496 d->bottomBorderStyle = style;
4497}
4498
4500{
4501 return d->bottomBorderColor;
4502}
4503
4505{
4506 d->bottomBorderColor = color;
4507}
4508
4510{
4511 return d->diagonalTopLeft;
4512}
4513
4515{
4516 d->diagonalTopLeft = dd;
4517}
4518
4520{
4521 return d->diagonalBottomLeft;
4522}
4523
4525{
4526 d->diagonalBottomLeft = dd;
4527}
4528
4530{
4531 return d->diagonalStyle;
4532}
4533
4534void XFRecord::setDiagonalStyle( unsigned style )
4535{
4536 d->diagonalStyle = style;
4537}
4538
4540{
4541 return d->diagonalColor;
4542}
4543
4544void XFRecord::setDiagonalColor( unsigned color )
4545{
4546 d->diagonalColor = color;
4547}
4548
4550{
4551 return d->fillPattern;
4552}
4553
4554void XFRecord::setFillPattern( unsigned pattern )
4555{
4556 d->fillPattern = pattern;
4557}
4558
4560{
4561 return d->patternForeColor;
4562}
4563
4564void XFRecord::setPatternForeColor( unsigned color )
4565{
4566 d->patternForeColor = color;
4567}
4568
4570{
4571 return d->patternBackColor;
4572}
4573
4574void XFRecord::setPatternBackColor( unsigned color )
4575{
4576 d->patternBackColor = color;
4577}
4578
4579void XFRecord::setData( unsigned size, const unsigned char* data )
4580{
4581 unsigned recordSize = ( version() == Excel97 ) ? 20: 16;
4582 if( size < recordSize ) return;
4583
4584 setFontIndex( readU16( data ) );
4585 setFormatIndex( readU16( data+2 ) );
4586
4587 unsigned protection = readU16( data+4 ) & 7;
4588 setLocked( protection & 1 );
4589 setFormulaHidden( protection & 2 );
4590
4591 setParentStyle( readU16( data+4 ) >> 4 );
4592
4593 unsigned align = data[6];
4594 setHorizontalAlignment( align & 0x07 );
4595 setVerticalAlignment( align >> 4 );
4596 setTextWrap( align & 0x08 );
4597
4598 unsigned angle = data[7];
4599 setRotationAngle( ( angle != 255 ) ? ( angle & 0x7f ) : 0 );
4600 setStackedLetters( angle == 255 );
4601
4602 if( version() == Excel97 )
4603 {
4604 unsigned options = data[8];
4605 unsigned attributes = data[9];
4606
4607 setIndentLevel( options & 0x0f );
4608 setShrinkContent( options & 0x10 );
4609
4610 unsigned linestyle = readU16( data + 10 );
4611 unsigned color1 = readU16( data + 12 );
4612 // unsigned color2 = readU16( data + 14 );
4613 unsigned flag = readU16( data + 16 );
4614 unsigned fill = readU16( data + 18 );
4615
4616 setLeftBorderStyle( linestyle & 0xf );
4617 setRightBorderStyle( ( linestyle >> 4 ) & 0xf );
4618 setTopBorderStyle( ( linestyle >> 8 ) & 0xf );
4619 setBottomBorderStyle( ( linestyle >> 12 ) & 0xf );
4620
4621 setLeftBorderColor( color1 & 0x7f );
4622 setRightBorderColor( ( color1 >> 7 ) & 0x7f );
4623 setTopBorderColor( color1 & 0x7f );
4624 setBottomBorderColor( ( color1 >> 7 ) & 0x7f );
4625
4626 setDiagonalTopLeft( color1 & 0x40 );
4627 setDiagonalBottomLeft( color1 & 0x40 );
4628 setDiagonalStyle( ( flag >> 4 ) & 0x1e );
4629 setDiagonalColor( ( ( flag & 0x1f ) << 2 ) + ( ( color1 >> 14 ) & 3 ));
4630
4631 setFillPattern( ( flag >> 10 ) & 0x3f );
4632 setPatternForeColor( fill & 0x7f );
4633 setPatternBackColor( ( fill >> 7 ) & 0x7f );
4634 }
4635 else
4636 {
4637 unsigned data1 = readU32( data + 8 );
4638 unsigned data2 = readU32( data + 12 );
4639
4640 setPatternForeColor( data1 & 0x7f );
4641 setPatternBackColor( ( data1 >> 7 ) & 0x7f );
4642 setFillPattern( ( data1 >> 16 ) & 0x3f );
4643
4644 setBottomBorderStyle( ( data1 >> 22 ) & 0x07 );
4645 setBottomBorderColor( ( data1 >> 25 ) & 0x7f );
4646
4647 setTopBorderStyle( data2 & 0x07 );
4648 setLeftBorderStyle( ( data2 >> 3 ) & 0x07 );
4649 setRightBorderStyle( ( data2 >> 6 ) & 0x07 );
4650
4651 setTopBorderColor( ( data2 >> 9 ) & 0x7f );
4652 setLeftBorderColor( ( data2 >> 16 ) & 0x7f );
4653 setRightBorderColor( ( data2 >> 23 ) & 0x7f );
4654 }
4655}
4656
4657void XFRecord::dump( std::ostream& out ) const
4658{
4659 out << "XF" << std::endl;
4660 out << " Parent Style : " << parentStyle() << std::endl;
4661 out << " Font Index : " << fontIndex() << std::endl;
4662 out << " Format Index : " << formatIndex() << std::endl;
4663 out << " Locked : " << (locked()?"Yes":"No") << std::endl;
4664 out << " Formula Visibility : " << (formulaHidden()?"Hidden":"Visible") << std::endl;
4665 out << " Horizontal Align : " << horizontalAlignmentAsString() << std::endl;
4666 out << " Vertical Align : " << verticalAlignmentAsString() << std::endl;
4667 out << " Text Wrap : " << ( textWrap() ? "yes" : "no" ) << std::endl;
4668 out << " Rotation : " << rotationAngle() << std::endl;
4669 out << " Stacked Letters : " << ( stackedLetters() ? "yes" : "no" ) << std::endl;
4670 out << " Indent Level : " << indentLevel() << std::endl;
4671 out << " Shrink To Fit : " << ( shrinkContent() ? "yes" : "no" ) << std::endl;
4672 out << " Left Border : Style " << leftBorderStyle();
4673 out << " Color: " << leftBorderColor() << std::endl;
4674 out << " Right Border : Style " << rightBorderStyle();
4675 out << " Color: " << rightBorderColor() << std::endl;
4676 out << " Top Border : Style " << topBorderStyle();
4677 out << " Color: " << topBorderColor() << std::endl;
4678 out << " Bottom Border : Style " << bottomBorderStyle();
4679 out << " Color: " << bottomBorderColor() << std::endl;
4680 out << " Diagonal Lines : " ;
4681 if ( diagonalTopLeft() ) out << "TopLeft ";
4682 if ( diagonalBottomLeft() ) out << "BottomLeft ";
4683 out << "Style " << diagonalStyle() << " Color: " << diagonalColor() << std::endl;
4684 out << " Fill Pattern : " << fillPattern() << std::endl;
4685 out << " Fill Color : Fore " << patternForeColor() << " Back: "
4686 << patternBackColor() << std::endl;
4687}
4688
4689//=============================================
4690// ExcelReader
4691//=============================================
4692
4693struct ExcelReaderExternalWorkbook
4694{
4695 bool addin;
4696 bool external;
4697 bool internal;
4698 bool objectLink;
4699};
4700
4701class ExcelReader::Private
4702{
4703public:
4704
4705 // the workbook
4706 Workbook* workbook;
4707
4708 // password protection flag
4709 // TODO: password hash for record decryption
4710 bool passwordProtected;
4711
4712 // active sheet, all cell records will be stored here
4713 Sheet* activeSheet;
4714
4715 // for FORMULA+STRING record pair
4716 Cell* formulaCell;
4717
4718 // mapping from BOF pos to actual Sheet
4719 std::map<unsigned,Sheet*> bofMap;
4720
4721 // shared-string table
4722 std::vector<UString> stringTable;
4723
4724 // table of format
4725 std::map<unsigned,FormatRecord> formatTable;
4726 std::map<unsigned,UString> formatsTable;
4727
4728 // table of font
4729 std::vector<FontRecord> fontTable;
4730
4731 // table of Xformat
4732 std::vector<XFRecord> xfTable;
4733
4734 // color table (from Palette record)
4735 std::vector<Color> colorTable;
4736
4737 // mapping from font index to Swinder::FormatFont
4738 std::map<unsigned,FormatFont> fontCache;
4739
4740 // for NAME and EXTERNNAME
4741 std::vector<UString> nameTable;
4742
4743 // for SUPBOOK
4744 std::vector<ExcelReaderExternalWorkbook> externalWorkbooks;
4745
4746 // for EXTERNSHEET
4747 std::vector<UString> sheetRefs;
4748
4749 // for mergeToken functions
4750 UString mergedTokens;
4751};
4752
4753ExcelReader::ExcelReader()
4754{
4755 d = new ExcelReader::Private();
4756
4757 d->workbook = 0;
4758 d->activeSheet = 0;
4759 d->formulaCell = 0;
4760
4761 d->passwordProtected = false;
4762
4763 d->mergedTokens.reserve(1024);
4764
4765 // initialize palette
4766 // default palette for all but the first 8 colors
4767 static const char *const default_palette[64-8] =
4768 {
4769 "#000000", "#ffffff", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff",
4770 "#00ffff", "#800000", "#008000", "#000080", "#808000", "#800080", "#008080",
4771 "#c0c0c0", "#808080", "#9999ff", "#993366", "#ffffcc", "#ccffff", "#660066",
4772 "#ff8080", "#0066cc", "#ccccff", "#000080", "#ff00ff", "#ffff00", "#00ffff",
4773 "#800080", "#800000", "#008080", "#0000ff", "#00ccff", "#ccffff", "#ccffcc",
4774 "#ffff99", "#99ccff", "#ff99cc", "#cc99ff", "#ffcc99", "#3366ff", "#33cccc",
4775 "#99cc00", "#ffcc00", "#ff9900", "#ff6600", "#666699", "#969696", "#003366",
4776 "#339966", "#003300", "#333300", "#993300", "#993366", "#333399", "#333333",
4777 };
4778 for( int i = 0; i < 64-8; i++ ) {
4779 d->colorTable.push_back(Color(default_palette[i]));
4780 }
4781
4782 // default number formats
4783 for( int format = 0; format < 50; format++)
4784 {
4785 UString valueFormat;
4786 switch(format)
4787 {
4788 case 0: break;
4789 case 1: valueFormat = "0"; break;
4790 case 2: valueFormat = "0.00"; break;
4791 case 3: valueFormat = "#,##0"; break;
4792 case 4: valueFormat = "#,##0.00"; break;
4793 case 5: valueFormat = "\"$\"#,##0_);(\"S\"#,##0)"; break;
4794 case 6: valueFormat = "\"$\"#,##0_);[Red](\"S\"#,##0)"; break;
4795 case 7: valueFormat = "\"$\"#,##0.00_);(\"S\"#,##0.00)"; break;
4796 case 8: valueFormat = "\"$\"#,##0.00_);[Red](\"S\"#,##0.00)"; break;
4797 case 9: valueFormat = "0%"; break;
4798 case 10: valueFormat = "0.00%"; break;
4799 case 11: valueFormat = "0.00E+00"; break;
4800 case 12: valueFormat = "#?/?"; break;
4801 case 13: valueFormat = "#\?\?/\?\?"; break;
4802 case 14: valueFormat = "M/D/YY"; break;
4803 case 15: valueFormat = "D-MMM-YY"; break;
4804 case 16: valueFormat = "D-MMM"; break;
4805 case 17: valueFormat = "MMM-YY"; break;
4806 case 18: valueFormat = "h:mm AM/PM"; break;
4807 case 19: valueFormat = "h:mm:ss AM/PM"; break;
4808 case 20: valueFormat = "h:mm"; break;
4809 case 21: valueFormat = "h:mm:ss"; break;
4810 case 22: valueFormat = "M/D/YY h:mm"; break;
4811 case 37: valueFormat = "_(#,##0_);(#,##0)"; break;
4812 case 38: valueFormat = "_(#,##0_);[Red](#,##0)"; break;
4813 case 39: valueFormat = "_(#,##0.00_);(#,##0)"; break;
4814 case 40: valueFormat = "_(#,##0.00_);[Red](#,##0)"; break;
4815 case 41: valueFormat = "_(\"$\"*#,##0_);_(\"$\"*#,##0_);_(\"$\"*\"-\");(@_)"; break;
4816 case 42: valueFormat = "_(*#,##0_);(*(#,##0);_(*\"-\");_(@_)"; break;
4817 case 43: valueFormat = "_(\"$\"*#,##0.00_);_(\"$\"*#,##0.00_);_(\"$\"*\"-\");(@_)"; break;
4818 case 44: valueFormat = "_(\"$\"*#,##0.00_);_(\"$\"*#,##0.00_);_(\"$\"*\"-\");(@_)"; break;
4819 case 45: valueFormat = "mm:ss"; break;
4820 case 46: valueFormat = "[h]:mm:ss"; break;
4821 case 47: valueFormat = "mm:ss.0"; break;
4822 case 48: valueFormat = "##0.0E+0"; break;
4823 case 49: valueFormat = "@"; break;
4824 }
4825 d->formatsTable[format] = valueFormat;
4826 }
4827}
4828
4829ExcelReader::~ExcelReader()
4830{
4831 delete d;
4832}
4833
4834
4835// convert border style, e.g MediumDashed to a Pen
4836static Pen convertBorderStyle( unsigned style )
4837{
4838 Pen pen;
4839 switch( style )
4840 {
4841 case XFRecord::NoLine:
4842 pen.width = 0;
4843 pen.style = Pen::NoLine;
4844 break;
4845 case XFRecord::Thin:
4846 pen.width = 1;
4847 pen.style = Pen::SolidLine;
4848 break;
4849 case XFRecord::Medium:
4850 pen.width = 3;
4851 pen.style = Pen::SolidLine;
4852 break;
4853 case XFRecord::Dashed:
4854 pen.width = 1;
4855 pen.style = Pen::DashLine;
4856 break;
4857 case XFRecord::Dotted:
4858 pen.width = 1;
4859 pen.style = Pen::DotLine;
4860 break;
4861 case XFRecord::Thick:
4862 pen.width = 4;
4863 pen.style = Pen::SolidLine;
4864 break;
4865 case XFRecord::Double:
4866 // FIXME no equivalent ?
4867 pen.width = 4;
4868 pen.style = Pen::SolidLine;
4869 break;
4870 case XFRecord::Hair:
4871 // FIXME no equivalent ?
4872 pen.width = 1;
4873 pen.style = Pen::DotLine;
4874 break;
4875 case XFRecord::MediumDashed:
4876 pen.width = 3;
4877 pen.style = Pen::DashLine;
4878 break;
4879 case XFRecord::ThinDashDotted:
4880 pen.width = 1;
4881 pen.style = Pen::DashDotLine;
4882 break;
4883 case XFRecord::MediumDashDotted:
4884 pen.width = 3;
4885 pen.style = Pen::DashDotLine;
4886 break;
4887 case XFRecord::ThinDashDotDotted:
4888 pen.width = 1;
4889 pen.style = Pen::DashDotDotLine;
4890 break;
4891 case XFRecord::MediumDashDotDotted:
4892 pen.width = 3;
4893 pen.style = Pen::DashDotDotLine;
4894 break;
4895 case XFRecord::SlantedMediumDashDotted:
4896 // FIXME no equivalent ?
4897 pen.width = 3;
4898 pen.style = Pen::DashDotLine;
4899 break;
4900 default:
4901 // fallback, simple solid line
4902 pen.width = 1;
4903 pen.style = Pen::SolidLine;
4904 break;
4905 };
4906
4907 return pen;
4908}
4909
4910unsigned convertPatternStyle( unsigned pattern )
4911{
4912 switch ( pattern )
4913 {
4914 case 0x00: return FormatBackground::EmptyPattern;
4915 case 0x01: return FormatBackground::SolidPattern;
4916 case 0x02: return FormatBackground::Dense4Pattern;
4917 case 0x03: return FormatBackground::Dense3Pattern;
4918 case 0x04: return FormatBackground::Dense5Pattern;
4919 case 0x05: return FormatBackground::HorPattern;
4920 case 0x06: return FormatBackground::VerPattern;
4921 case 0x07: return FormatBackground::FDiagPattern;
4922 case 0x08: return FormatBackground::BDiagPattern;
4923 case 0x09: return FormatBackground::Dense1Pattern;
4924 case 0x0A: return FormatBackground::Dense2Pattern;
4925 case 0x0B: return FormatBackground::HorPattern;
4926 case 0x0C: return FormatBackground::VerPattern;
4927 case 0x0D: return FormatBackground::FDiagPattern;
4928 case 0x0E: return FormatBackground::BDiagPattern;
4929 case 0x0F: return FormatBackground::CrossPattern;
4930 case 0x10: return FormatBackground::DiagCrossPattern;
4931 case 0x11: return FormatBackground::Dense6Pattern;
4932 case 0x12: return FormatBackground::Dense7Pattern;
4933 default: return FormatBackground::SolidPattern; // fallback
4934 }
4935}
4936
4937
4938bool ExcelReader::load( Workbook* workbook, const char* filename )
4939{
4940 POLE::Storage storage( filename );
4941 if( !storage.open() )
4942 {
4943 //std::cerr << "Cannot open " << filename << std::endl;
4944 return false;
4945 }
4946
4947 unsigned version = Swinder::Excel97;
4948 POLE::Stream* stream;
4949 stream = new POLE::Stream( &storage, "/Workbook" );
4950 if( stream->fail() )
4951 {
4952 delete stream;
4953 stream = new POLE::Stream( &storage, "/Book" );
4954 version = Swinder::Excel95;
4955 }
4956
4957 if( stream->fail() )
4958 {
4959 //std::cerr << filename << " is not Excel workbook" << std::endl;
4960 delete stream;
4961 return false;
4962 }
4963
4964 unsigned long stream_size = stream->size();
4965
4966 unsigned int buffer_size = 65536; // current size of the buffer
4967 unsigned char *buffer = (unsigned char *) malloc(buffer_size);
4968 unsigned char small_buffer[128]; // small, fixed size buffer
4969
4970 workbook->clear();
4971 d->workbook = workbook;
4972
4973 d->passwordProtected = false;
4974
4975 // assume
4976
4977 while( stream->tell() < stream_size )
4978 {
4979
4980 // this is set by FILEPASS record
4981 // subsequent records will need to be decrypted
4982 // since we do not support it yet, we have to bail out
4983 if(d->passwordProtected)
4984 {
4985 d->workbook->setPasswordProtected( true );
4986 break;
4987 }
4988
4989 // get record type and data size
4990 unsigned long pos = stream->tell();
4991 unsigned bytes_read = stream->read( buffer, 4 );
4992 if( bytes_read != 4 ) break;
4993
4994 unsigned long type = readU16( buffer );
4995 unsigned long size = readU16( buffer + 2 );
4996
4997 // verify buffer is large enough to hold the record data
4998 if (size > buffer_size) {
4999 buffer = (unsigned char *) realloc(buffer, size);
5000 buffer_size = size;
5001 }
5002
5003 // load actual record data
5004 bytes_read = stream->read( buffer, size );
5005 if( bytes_read != size ) break;
5006
5007 // save current position in stream, to be able to restore the position later on
5008 unsigned long saved_pos;
5009 // repeatedly check if the next record is type 0x3C, a continuation record
5010 unsigned long next_type; // the type of the next record
5011 do {
5012 saved_pos = stream->tell();
5013
5014 bytes_read = stream->read( small_buffer, 4 );
5015 if (bytes_read != 4) break;
5016
5017 next_type = readU16( small_buffer );
5018 unsigned long next_size = readU16( small_buffer + 2 );
5019
5020 if (next_type == 0x3C) {
5021 // type of next record is 0x3C, so go ahead and append the contents of the next record to the buffer
5022
5023 // first verify the buffer is large enough to hold all the data
5024 if ( (size + next_size) > buffer_size) {
5025 buffer = (unsigned char *) realloc(buffer, size + next_size);
5026 buffer_size = size + next_size;
5027 }
5028
5029 // next read the data of the record
5030 bytes_read = stream->read( buffer + size, next_size );
5031 if (bytes_read != next_size) {
5032 std::cout << "ERROR!" << std::endl;
5033 break;
5034 }
5035
5036 // if the first read byte is a zero, remove it (at least that is what the old excel97 filter did...)
5037 if (buffer[size] == 0) {
5038 memmove( buffer + size, buffer + size + 1, --next_size );
5039 }
5040
5041 // and finally update size
5042 size += next_size;
5043 }
5044 } while (next_type == 0x3C);
5045
5046 // restore position in stream to the beginning of the next record
5047 stream->seek( saved_pos );
5048
5049 // skip record type 0, this is just for filler
5050 if( type == 0 ) continue;
5051
5052 // create the record using the factory
5053 Record* record = Record::create( type );
5054
5055 if( record )
5056 {
5057 // setup the record and invoke handler
5058 record->setVersion( version );
5059 record->setData( size, buffer );
5060 record->setPosition( pos );
5061
5062 handleRecord( record );
5063
5064 // special handling to find Excel version
5065 if ( record->rtti() == BOFRecord::id )
5066 {
5067 BOFRecord* bof = static_cast<BOFRecord*>(record);
5068 if( bof ) if( bof->type() == BOFRecord::Workbook )
5069 version = bof->version();
5070 }
5071
5072#ifdef SWINDER_XLS2RAW
5073 std::cout << "Record 0x";
5074 std::cout << std::setfill('0') << std::setw(4) << std::hex << record->rtti();
5075 std::cout << " ";
5076 std::cout << std::dec;
5077 std::cout << "(Pos: " << record->position() << ") ";
5078 record->dump( std::cout );
5079 std::cout << std::endl;
5080#endif
5081
5082 delete record;
5083 }
5084
5085#ifdef SWINDER_XLS2RAW
5086 if( !record )
5087 {
5088 std::cout << "Record 0x";
5089 std::cout << std::setfill('0') << std::setw(4) << std::hex << type;
5090 std::cout << std::dec;
5091 std::cout << "(Pos: " << pos << ") ";
5092 std::cout << std::endl;
5093 std::cout << std::endl;
5094 }
5095#endif
5096
5097 }
5098
5099 free(buffer);
5100
5101 delete stream;
5102
5103 storage.close();
5104
5105 // for each XF, create the corresponding format
5106 for(int i = 0; i < d->xfTable.size(); i++ )
5107 {
5108 Format format;
5109 const XFRecord& xf = d->xfTable[i];
5110
5111 UString valueFormat = d->formatsTable[xf.formatIndex()];
5112 format.setValueFormat( valueFormat );
5113
5114 format.setFont( convertFont( xf.fontIndex() ) );
5115
5116 FormatAlignment alignment;
5117 switch( xf.horizontalAlignment() )
5118 {
5119 case XFRecord::Left:
5120 alignment.setAlignX( Format::Left ); break;
5121 case XFRecord::Right:
5122 alignment.setAlignX( Format::Right ); break;
5123 case XFRecord::Centered:
5124 alignment.setAlignX( Format::Center ); break;
5125 default: break;
5126 // FIXME still unsupported: Repeat, Justified, Filled, Distributed
5127 };
5128 switch( xf.verticalAlignment() )
5129 {
5130 case XFRecord::Top:
5131 alignment.setAlignY( Format::Top ); break;
5132 case XFRecord::VCentered:
5133 alignment.setAlignY( Format::Middle ); break;
5134 case XFRecord::Bottom:
5135 alignment.setAlignY( Format::Bottom ); break;
5136 default: break;
5137 // FIXME still unsupported: Justified, Distributed
5138 }
5139 alignment.setWrap( xf.textWrap() );
5140 format.setAlignment( alignment );
5141
5142 FormatBorders borders;
5143
5144 Pen pen;
5145 pen = convertBorderStyle( xf.leftBorderStyle() );
5146 pen.color = convertColor( xf.leftBorderColor() );
5147 borders.setLeftBorder( pen );
5148
5149 pen = convertBorderStyle( xf.rightBorderStyle() );
5150 pen.color = convertColor( xf.rightBorderColor() );
5151 borders.setRightBorder( pen );
5152
5153 pen = convertBorderStyle( xf.topBorderStyle() );
5154 pen.color = convertColor( xf.topBorderColor() );
5155 borders.setTopBorder( pen );
5156
5157 pen = convertBorderStyle( xf.bottomBorderStyle() );
5158 pen.color = convertColor( xf.bottomBorderColor() );
5159 borders.setBottomBorder( pen );
5160
5161 format.setBorders( borders );
5162
5163 FormatBackground background;
5164 background.setForegroundColor( convertColor( xf.patternForeColor() ) );
5165 background.setBackgroundColor( convertColor( xf.patternBackColor() ) );
5166 background.setPattern( convertPatternStyle( xf.fillPattern() ) );
5167 format.setBackground( background );
5168
5169 d->workbook->setFormat( i, format );
5170
5171 }
5172
5173 return true;
5174}
5175
5176void ExcelReader::handleRecord( Record* record )
5177{
5178 if( !record ) return;
5179
5180 unsigned type = record->rtti();
5181 switch( type )
5182 {
5184 handleBottomMargin( static_cast<BottomMarginRecord*>( record ) ); break;
5186 handleBoundSheet( static_cast<BoundSheetRecord*>( record ) ); break;
5187 case BOFRecord::id:
5188 handleBOF( static_cast<BOFRecord*>( record ) ); break;
5189 case BoolErrRecord::id:
5190 handleBoolErr( static_cast<BoolErrRecord*>( record ) ); break;
5191 case BlankRecord::id:
5192 handleBlank( static_cast<BlankRecord*>( record ) ); break;
5193 case CalcModeRecord::id:
5194 handleCalcMode( static_cast<CalcModeRecord*>( record ) ); break;
5195 case ColInfoRecord::id:
5196 handleColInfo( static_cast<ColInfoRecord*>( record ) ); break;
5198 handleExternName( static_cast<ExternNameRecord*>( record ) ); break;
5200 handleExternSheet( static_cast<ExternSheetRecord*>( record ) ); break;
5201 case FilepassRecord::id:
5202 handleFilepass( static_cast<FilepassRecord*>( record ) ); break;
5203 case FormatRecord::id:
5204 handleFormat( static_cast<FormatRecord*>( record ) ); break;
5205 case FormulaRecord::id:
5206 handleFormula( static_cast<FormulaRecord*>( record ) ); break;
5207 case FontRecord::id:
5208 handleFont( static_cast<FontRecord*>( record ) ); break;
5209 case FooterRecord::id:
5210 handleFooter( static_cast<FooterRecord*>( record ) ); break;
5211 case HeaderRecord::id:
5212 handleHeader( static_cast<HeaderRecord*>( record ) ); break;
5213 case LabelRecord::id:
5214 handleLabel( static_cast<LabelRecord*>( record ) ); break;
5215 case LabelSSTRecord::id:
5216 handleLabelSST( static_cast<LabelSSTRecord*>( record ) ); break;
5218 handleLeftMargin( static_cast<LeftMarginRecord*>( record ) ); break;
5220 handleMergedCells( static_cast<MergedCellsRecord*>( record ) ); break;
5221 case MulBlankRecord::id:
5222 handleMulBlank( static_cast<MulBlankRecord*>( record ) ); break;
5223 case MulRKRecord::id:
5224 handleMulRK( static_cast<MulRKRecord*>( record ) ); break;
5225 case NameRecord::id:
5226 handleName( static_cast<NameRecord*>( record ) ); break;
5227 case NumberRecord::id:
5228 handleNumber( static_cast<NumberRecord*>( record ) ); break;
5229 case PaletteRecord::id:
5230 handlePalette( static_cast<PaletteRecord*>( record ) ); break;
5232 handleRightMargin( static_cast<RightMarginRecord*>( record ) ); break;
5233 case RKRecord::id:
5234 handleRK( static_cast<RKRecord*>( record ) ); break;
5235 case RowRecord::id:
5236 handleRow( static_cast<RowRecord*>( record ) ); break;
5237 case RStringRecord::id:
5238 handleRString( static_cast<RStringRecord*>( record ) ); break;
5239 case SSTRecord::id:
5240 handleSST( static_cast<SSTRecord*>( record ) ); break;
5241 case StringRecord::id:
5242 handleString( static_cast<StringRecord*>( record ) ); break;
5243 case SupbookRecord::id:
5244 handleSupbook( static_cast<SupbookRecord*>( record ) ); break;
5245 case TopMarginRecord::id:
5246 handleTopMargin( static_cast<TopMarginRecord*>( record ) ); break;
5247 case XFRecord::id:
5248 handleXF( static_cast<XFRecord*>( record ) ); break;
5249 default:
5250 break;
5251 }
5252}
5253
5254void ExcelReader::handleBottomMargin( BottomMarginRecord* record )
5255{
5256 if( !record ) return;
5257
5258 if( !d->activeSheet ) return;
5259
5260 // convert from inches to points
5261 double margin = record->bottomMargin() * 72.0;
5262 d->activeSheet->setBottomMargin( margin );
5263}
5264
5265// FIXME does the order of sheet follow BOUNDSHEET of BOF(Worksheet) ?
5266// for now, assume BOUNDSHEET, hence we should create the sheet here
5267void ExcelReader::handleBoundSheet( BoundSheetRecord* record )
5268{
5269 if( !record ) return;
5270
5271 // only care for Worksheet, forget everything else
5272 if( record->type() == BoundSheetRecord::Worksheet )
5273 {
5274 // create a new sheet
5275 Sheet* sheet = new Sheet( d->workbook );
5276 sheet->setName( record->sheetName() );
5277 sheet->setVisible( record->visible() );
5278
5279 d->workbook->appendSheet( sheet );
5280
5281 // update bof position map
5282 unsigned bofPos = record->bofPosition();
5283 d->bofMap[ bofPos ] = sheet;
5284 }
5285}
5286
5287void ExcelReader::handleBOF( BOFRecord* record )
5288{
5289 if( !record ) return;
5290
5291 if( record->type() == BOFRecord::Worksheet )
5292 {
5293 // find the sheet and make it active
5294 // which sheet ? look from from previous BoundSheet
5295 Sheet* sheet = d->bofMap[ record->position() ];
5296 if( sheet ) d->activeSheet = sheet;
5297 }
5298}
5299
5300void ExcelReader::handleBoolErr( BoolErrRecord* record )
5301{
5302 if( !record ) return;
5303
5304 if( !d->activeSheet ) return;
5305
5306 unsigned column = record->column();
5307 unsigned row = record->row();
5308 unsigned xfIndex = record->xfIndex();
5309
5310 Cell* cell = d->activeSheet->cell( column, row, true );
5311 if( cell )
5312 {
5313 cell->setValue( record->value() );
5314 cell->setFormatIndex( xfIndex );
5315 }
5316}
5317
5318void ExcelReader::handleBlank( BlankRecord* record )
5319{
5320 if( !record ) return;
5321
5322 if( !d->activeSheet ) return;
5323
5324 unsigned column = record->column();
5325 unsigned row = record->row();
5326 unsigned xfIndex = record->xfIndex();
5327
5328 Cell* cell = d->activeSheet->cell( column, row, true );
5329 if( cell )
5330 {
5331 cell->setFormatIndex( xfIndex );
5332 }
5333}
5334
5335void ExcelReader::handleCalcMode( CalcModeRecord* record )
5336{
5337 if( !record ) return;
5338
5339 d->workbook->setAutoCalc( record->autoCalc() );
5340}
5341
5342void ExcelReader::handleColInfo( ColInfoRecord* record )
5343{
5344 if( !record ) return;
5345
5346 if( !d->activeSheet ) return;
5347
5348 unsigned firstColumn = record->firstColumn();
5349 unsigned lastColumn = record->lastColumn();
5350 unsigned xfIndex = record->xfIndex();
5351 unsigned width = record->width();
5352 bool hidden = record->hidden();
5353
5354 for( unsigned i = firstColumn; i <= lastColumn; i++ )
5355 {
5356 Column* column = d->activeSheet->column( i, true );
5357 if( column )
5358 {
5359 column->setWidth( width / 120 );
5360 column->setFormatIndex( xfIndex );
5361 column->setVisible( !hidden );
5362 }
5363 }
5364}
5365
5366void ExcelReader::handleDateMode( DateModeRecord* record )
5367{
5368 if( !record ) return;
5369
5370 // FIXME FIXME what to do ??
5371 std::cerr << "WARNING: Workbook uses unsupported 1904 Date System " << std::endl;
5372}
5373
5374void ExcelReader::handleDimension( DimensionRecord* record )
5375{
5376 if( !record ) return;
5377
5378 // in the mean time we don't need to handle this because we don't care
5379 // about the used range of the sheet
5380}
5381
5382void ExcelReader::handleLabel( LabelRecord* record )
5383{
5384 if( !record ) return;
5385
5386 if( !d->activeSheet ) return;
5387
5388 unsigned column = record->column();
5389 unsigned row = record->row();
5390 unsigned xfIndex = record->xfIndex();
5391 UString label = record->label();
5392
5393 Cell* cell = d->activeSheet->cell( column, row, true );
5394 if( cell )
5395 {
5396 cell->setValue( Value( label ) );
5397 cell->setFormatIndex( xfIndex );
5398 }
5399}
5400
5401void ExcelReader::handleLeftMargin( LeftMarginRecord* record )
5402{
5403 if( !record ) return;
5404
5405 if( !d->activeSheet ) return;
5406
5407 // convert from inches to points
5408 double margin = record->leftMargin() * 72.0;
5409 d->activeSheet->setLeftMargin( margin );
5410}
5411
5412void ExcelReader::handleFormat( FormatRecord* record )
5413{
5414 if( !record ) return;
5415
5416 d->formatTable[ record->index() ] = *record;
5417 d->formatsTable[ record->index() ] = record->formatString();
5418}
5419
5420void ExcelReader::handleFormula( FormulaRecord* record )
5421{
5422 if( !record ) return;
5423
5424 if( !d->activeSheet ) return;
5425
5426 unsigned column = record->column();
5427 unsigned row = record->row();
5428 unsigned xfIndex = record->xfIndex();
5429 Value value = record->result();
5430
5431#if 1
5432 // this gives the formula in OpenDocument format, e.g. "=SUM([A1]; [A2])
5433 UString formula = decodeFormula( row, column, record->tokens(), true );
5434#else
5435 // this gives the formula in standard Excel format, e.g. "=SUM(A1, A2)
5436 UString formula = decodeFormula( row, column, record->tokens(), true );
5437#endif
5438
5439 Cell* cell = d->activeSheet->cell( column, row, true );
5440 if( cell )
5441 {
5442 cell->setValue( value );
5443 if( !formula.isEmpty() )
5444 cell->setFormula( formula );
5445 cell->setFormatIndex( xfIndex );
5446
5447 // if value is string, real value is in subsequent String record
5448 if( value.isString() )
5449 d->formulaCell = cell;
5450 }
5451}
5452
5453void ExcelReader::handleExternName( ExternNameRecord* record )
5454{
5455 if( !record ) return;
5456
5457 d->nameTable.push_back( record->externName() );
5458}
5459
5460void ExcelReader::handleExternSheet( ExternSheetRecord* record )
5461{
5462 if( !record ) return;
5463
5464 if(record->version() >= Excel97)
5465 for(unsigned i = 0; i < record->count(); i++)
5466 {
5467 UString decodedRef("#REF");
5468
5469 unsigned index = record->refIndex(i);
5470 unsigned first = record->firstSheet(i);
5471 unsigned last = record->lastSheet(i);
5472
5473 if(index < d->externalWorkbooks.size())
5474 {
5475 // handle reference to own workbook
5476 if(d->externalWorkbooks[index].internal)
5477 if(first < d->workbook->sheetCount())
5478 decodedRef = d->workbook->sheet(first)->name();
5479
5480 // add-in? let's (re)use # marker as in Excel 95
5481 if(d->externalWorkbooks[index].addin)
5482 decodedRef = UString("#");
5483 }
5484
5485 d->sheetRefs.push_back(decodedRef);
5486 }
5487 else
5488 {
5489 UString ref = record->refName();
5490 d->sheetRefs.push_back(ref);
5491 }
5492}
5493
5494void ExcelReader::handleFilepass( FilepassRecord* record )
5495{
5496 if( !record ) return;
5497
5498 d->passwordProtected = true;
5499}
5500
5501void ExcelReader::handleFont( FontRecord* record )
5502{
5503 if( !record ) return;
5504
5505 d->fontTable.push_back( *record );
5506
5507 // font #4 is never used, so add a dummy one
5508 if( d->fontTable.size() == 4 )
5509 d->fontTable.push_back( FontRecord() );
5510}
5511
5512void ExcelReader::handleFooter( FooterRecord* record )
5513{
5514 if( !record ) return;
5515
5516 if( !d->activeSheet ) return;
5517
5518 UString footer = record->footer();
5519 UString left, center, right;
5520 int pos = -1, len = 0;
5521
5522 // left part
5523 pos = footer.find( UString("&L") );
5524 if( pos >= 0 )
5525 {
5526 pos += 2;
5527 len = footer.find( UString("&C") ) - pos;
5528 if( len > 0 )
5529 {
5530 left = footer.substr( pos, len );
5531 footer = footer.substr( pos+len, footer.length() );
5532 }
5533 }
5534
5535 // center part
5536 pos = footer.find( UString("&C") );
5537 if( pos >= 0 )
5538 {
5539 pos += 2;
5540 len = footer.find( UString("&R") ) - pos;
5541 if( len > 0 )
5542 {
5543 center = footer.substr( pos, len );
5544 footer = footer.substr( pos+len, footer.length() );
5545 }
5546 }
5547
5548 // right part
5549 pos = footer.find( UString("&R") );
5550 if( pos >= 0 )
5551 {
5552 pos += 2;
5553 right = footer.substr( pos, footer.length() - pos );
5554 }
5555
5556 d->activeSheet->setLeftFooter( left );
5557 d->activeSheet->setCenterFooter( center );
5558 d->activeSheet->setRightFooter( right );
5559}
5560
5561void ExcelReader::handleHeader( HeaderRecord* record )
5562{
5563 if( !record ) return;
5564
5565 if( !d->activeSheet ) return;
5566
5567 UString header = record->header();
5568 UString left, center, right;
5569 int pos = -1, len = 0;
5570
5571 // left part of the header
5572 pos = header.find( UString("&L") );
5573 if( pos >= 0 )
5574 {
5575 pos += 2;
5576 len = header.find( UString("&C") ) - pos;
5577 if( len > 0 )
5578 {
5579 left = header.substr( pos, len );
5580 header = header.substr( pos+len, header.length() );
5581 }
5582 }
5583
5584 // center part of the header
5585 pos = header.find( UString("&C") );
5586 if( pos >= 0 )
5587 {
5588 pos += 2;
5589 len = header.find( UString("&R") ) - pos;
5590 if( len > 0 )
5591 {
5592 center = header.substr( pos, len );
5593 header = header.substr( pos+len, header.length() );
5594 }
5595 }
5596
5597 // right part of the header
5598 pos = header.find( UString("&R") );
5599 if( pos >= 0 )
5600 {
5601 pos += 2;
5602 right = header.substr( pos, header.length() - pos );
5603 }
5604
5605 d->activeSheet->setLeftHeader( left );
5606 d->activeSheet->setCenterHeader( center );
5607 d->activeSheet->setRightHeader( right );
5608}
5609
5610void ExcelReader::handleLabelSST( LabelSSTRecord* record )
5611{
5612 if( !record ) return;
5613
5614 if( !d->activeSheet ) return;
5615
5616 unsigned column = record->column();
5617 unsigned row = record->row();
5618 unsigned index = record->sstIndex();
5619 unsigned xfIndex = record->xfIndex();
5620
5621 UString str;
5622 if( index < d->stringTable.size() )
5623 str = d->stringTable[ index ];
5624
5625 Cell* cell = d->activeSheet->cell( column, row, true );
5626 if( cell )
5627 {
5628 cell->setValue( Value( str ) );
5629 cell->setFormatIndex( xfIndex );
5630 }
5631}
5632
5633void ExcelReader::handleMergedCells( MergedCellsRecord* record )
5634{
5635 if( !record ) return;
5636
5637 if( !d->activeSheet ) return;
5638
5639 for( unsigned i = 0; i < record->count(); i++ )
5640 {
5641 unsigned firstRow = record->firstRow( i );
5642 unsigned lastRow = record->lastRow( i );
5643 unsigned firstColumn = record->firstColumn( i );
5644 unsigned lastColumn = record->lastColumn( i );
5645
5646 Cell* cell = d->activeSheet->cell( firstColumn, firstRow, true );
5647 if( cell )
5648 {
5649 cell->setColumnSpan( lastColumn - firstColumn + 1 );
5650 cell->setRowSpan( lastRow - firstRow + 1 );
5651 }
5652 }
5653}
5654
5655void ExcelReader::handleMulBlank( MulBlankRecord* record )
5656{
5657 if( !record ) return;
5658
5659 if( !d->activeSheet ) return;
5660
5661 unsigned firstColumn = record->firstColumn();
5662 unsigned lastColumn = record->lastColumn();
5663 unsigned row = record->row();
5664
5665 for( unsigned column = firstColumn; column <= lastColumn; column++ )
5666 {
5667 Cell* cell = d->activeSheet->cell( column, row, true );
5668 if( cell )
5669 {
5670 cell->setFormatIndex( record->xfIndex( column - firstColumn ) );
5671 }
5672 }
5673}
5674
5675void ExcelReader::handleMulRK( MulRKRecord* record )
5676{
5677 if( !record ) return;
5678
5679 if( !d->activeSheet ) return;
5680
5681 unsigned firstColumn = record->firstColumn();
5682 unsigned lastColumn = record->lastColumn();
5683 unsigned row = record->row();
5684
5685 for( unsigned column = firstColumn; column <= lastColumn; column++ )
5686 {
5687 Cell* cell = d->activeSheet->cell( column, row, true );
5688 if( cell )
5689 {
5690 unsigned i = column - firstColumn;
5691 Value value;
5692 if( record->isInteger( i ) )
5693 value.setValue( record->asInteger( i ) );
5694 else
5695 value.setValue( record->asFloat( i ) );
5696 cell->setValue( value );
5697 cell->setFormatIndex( record->xfIndex( column-firstColumn ) );
5698 }
5699 }
5700}
5701
5702void ExcelReader::handleName( NameRecord* record )
5703{
5704 if( !record ) return;
5705
5706 d->nameTable.push_back( record->definedName() );
5707}
5708
5709void ExcelReader::handleNumber( NumberRecord* record )
5710{
5711 if( !record ) return;
5712
5713 if( !d->activeSheet ) return;
5714
5715 unsigned column = record->column();
5716 unsigned row = record->row();
5717 unsigned xfIndex = record->xfIndex();
5718 double number = record->number();
5719
5720 Cell* cell = d->activeSheet->cell( column, row, true );
5721 if( cell )
5722 {
5723 cell->setValue( Value( number ) );
5724 cell->setFormatIndex( xfIndex );
5725 }
5726}
5727
5728void ExcelReader::handlePalette( PaletteRecord* record )
5729{
5730 if( !record ) return;
5731
5732 d->colorTable.clear();
5733 for( unsigned i = 0; i < record->count(); i++ )
5734 d->colorTable.push_back( record->color( i ) );
5735}
5736
5737void ExcelReader::handleRightMargin( RightMarginRecord* record )
5738{
5739 if( !record ) return;
5740
5741 if( !d->activeSheet ) return;
5742
5743 // convert from inches to points
5744 double margin = record->rightMargin() * 72.0;
5745 d->activeSheet->setRightMargin( margin );
5746}
5747
5748void ExcelReader::handleRK( RKRecord* record )
5749{
5750 if( !record ) return;
5751
5752 if( !d->activeSheet ) return;
5753
5754 unsigned column = record->column();
5755 unsigned row = record->row();
5756 unsigned xfIndex = record->xfIndex();
5757
5758 Value value;
5759 if( record->isInteger() )
5760 value.setValue( record->asInteger() );
5761 else
5762 value.setValue( record->asFloat() );
5763
5764 Cell* cell = d->activeSheet->cell( column, row, true );
5765 if( cell )
5766 {
5767 cell->setValue( value );
5768 cell->setFormatIndex( xfIndex );
5769 }
5770}
5771
5772void ExcelReader::handleRow( RowRecord* record )
5773{
5774 if( !record ) return;
5775
5776 if( !d->activeSheet ) return;
5777
5778 unsigned index = record->row();
5779 unsigned xfIndex = record->xfIndex();
5780 unsigned height = record->height();
5781 bool hidden = record->hidden();
5782
5783 Row* row = d->activeSheet->row( index, true );
5784 if( row )
5785 {
5786 row->setHeight( height / 20.0 );
5787 row->setFormatIndex( xfIndex );
5788 row->setVisible( !hidden );
5789 }
5790}
5791
5792void ExcelReader::handleRString( RStringRecord* record )
5793{
5794 if( !record ) return;
5795
5796 if( !d->activeSheet ) return;
5797
5798 unsigned column = record->column();
5799 unsigned row = record->row();
5800 unsigned xfIndex = record->xfIndex();
5801 UString label = record->label();
5802
5803 Cell* cell = d->activeSheet->cell( column, row, true );
5804 if( cell )
5805 {
5806 cell->setValue( Value( label ) );
5807 cell->setFormatIndex( xfIndex );
5808 }
5809}
5810
5811void ExcelReader::handleSST( SSTRecord* record )
5812{
5813 if( !record ) return;
5814
5815 d->stringTable.clear();
5816 for( unsigned i = 0; i < record->count();i++ )
5817 {
5818 UString str = record->stringAt( i );
5819 d->stringTable.push_back( str );
5820 }
5821}
5822
5823void ExcelReader::handleString( StringRecord* record )
5824{
5825 if( !record ) return;
5826
5827 if( !d->activeSheet ) return;
5828 if( !d->formulaCell ) return;
5829
5830 d->formulaCell->setValue( record->value() );
5831
5832 d->formulaCell = 0;
5833}
5834
5835void ExcelReader::handleSupbook( SupbookRecord* record )
5836{
5837 if( !record ) return;
5838
5839 ExcelReaderExternalWorkbook ext;
5840 ext.addin = record->referenceType() == SupbookRecord::AddInRef;
5841 ext.internal = record->referenceType() == SupbookRecord::InternalRef;
5842 ext.external = record->referenceType() == SupbookRecord::ExternalRef;
5843 ext.objectLink = record->referenceType() == SupbookRecord::ObjectLink;
5844 d->externalWorkbooks.push_back(ext);
5845}
5846
5847void ExcelReader::handleTopMargin( TopMarginRecord* record )
5848{
5849 if( !record ) return;
5850
5851 if( !d->activeSheet ) return;
5852
5853
5854 // convert from inches to points
5855 double margin = record->topMargin() * 72.0;
5856 d->activeSheet->setTopMargin( margin );
5857}
5858
5859FormatFont ExcelReader::convertFont( unsigned fontIndex )
5860{
5861 // speed-up trick: check in the cache first
5862 FormatFont font = d->fontCache[ fontIndex ];
5863 if( font.isNull() && ( fontIndex < d->fontTable.size() ))
5864 {
5865 FontRecord fr = d->fontTable[ fontIndex ];
5866 font.setFontSize( fr.height() / 20.0 );
5867 font.setFontFamily( fr.fontName() );
5868 font.setColor( convertColor( fr.colorIndex() ) );
5869 font.setBold( fr.boldness() > 500 );
5870 font.setItalic( fr.italic() );
5871 font.setStrikeout( fr.strikeout() );
5872 font.setSubscript( fr.escapement() == FontRecord::Subscript );
5873 font.setSuperscript( fr.escapement() == FontRecord::Superscript );
5874 font.setUnderline( fr.underline() != FontRecord::None );
5875
5876 // put in the cache for further use
5877 d->fontCache[ fontIndex ] = font;
5878 }
5879
5880 return font;
5881}
5882
5883Color ExcelReader::convertColor( unsigned colorIndex )
5884{
5885 if( ( colorIndex >= 8 ) && ( colorIndex < 0x40 ) )
5886 if( colorIndex-8 < d->colorTable.size() )
5887 return d->colorTable[ colorIndex-8 ];
5888
5889 // FIXME the following colors depend on system color settings
5890 // 0x0040 system window text colour for border lines
5891 // 0x0041 system window background colour for pattern background
5892 // 0x7fff system window text colour for fonts
5893 if( colorIndex == 0x40 ) return Color( 0, 0, 0 );
5894 if( colorIndex == 0x41 ) return Color( 255, 255, 255 );
5895 if( colorIndex == 0x7fff ) return Color( 0, 0, 0 );
5896
5897 // fallback: just "black"
5898 Color color;
5899
5900 // standard colors: black, white, red, green, blue,
5901 // yellow, magenta, cyan
5902 switch( colorIndex )
5903 {
5904 case 0: color = Color( 0, 0, 0 ); break;
5905 case 1: color = Color( 255, 255, 255 ); break;
5906 case 2: color = Color( 255, 0, 0 ); break;
5907 case 3: color = Color( 0, 255, 0 ); break;
5908 case 4: color = Color( 0, 0, 255 ); break;
5909 case 5: color = Color( 255, 255, 0 ); break;
5910 case 6: color = Color( 255, 0, 255 ); break;
5911 case 7: color = Color( 0, 255, 255 ); break;
5912 default: break;
5913 }
5914
5915 return color;
5916}
5917
5918// big task: convert Excel XFormat into Swinder::Format
5919Format ExcelReader::convertFormat( unsigned xfIndex )
5920{
5921 Format format;
5922
5923 if( xfIndex >= d->xfTable.size() ) return format;
5924
5925 XFRecord xf = d->xfTable[ xfIndex ];
5926
5927 UString valueFormat = d->formatsTable[xf.formatIndex()];
5928 format.setValueFormat( valueFormat );
5929
5930 format.setFont( convertFont( xf.fontIndex() ) );
5931
5932 FormatAlignment alignment;
5933 switch( xf.horizontalAlignment() )
5934 {
5935 case XFRecord::Left:
5936 alignment.setAlignX( Format::Left ); break;
5937 case XFRecord::Right:
5938 alignment.setAlignX( Format::Right ); break;
5939 case XFRecord::Centered:
5940 alignment.setAlignX( Format::Center ); break;
5941 default: break;
5942 // FIXME still unsupported: Repeat, Justified, Filled, Distributed
5943 };
5944 switch( xf.verticalAlignment() )
5945 {
5946 case XFRecord::Top:
5947 alignment.setAlignY( Format::Top ); break;
5948 case XFRecord::VCentered:
5949 alignment.setAlignY( Format::Middle ); break;
5950 case XFRecord::Bottom:
5951 alignment.setAlignY( Format::Bottom ); break;
5952 default: break;
5953 // FIXME still unsupported: Justified, Distributed
5954 }
5955 alignment.setWrap( xf.textWrap() );
5956 format.setAlignment( alignment );
5957
5958 FormatBorders borders;
5959
5960 Pen pen;
5961 pen = convertBorderStyle( xf.leftBorderStyle() );
5962 pen.color = convertColor( xf.leftBorderColor() );
5963 borders.setLeftBorder( pen );
5964
5965 pen = convertBorderStyle( xf.rightBorderStyle() );
5966 pen.color = convertColor( xf.rightBorderColor() );
5967 borders.setRightBorder( pen );
5968
5969 pen = convertBorderStyle( xf.topBorderStyle() );
5970 pen.color = convertColor( xf.topBorderColor() );
5971 borders.setTopBorder( pen );
5972
5973 pen = convertBorderStyle( xf.bottomBorderStyle() );
5974 pen.color = convertColor( xf.bottomBorderColor() );
5975 borders.setBottomBorder( pen );
5976
5977 format.setBorders( borders );
5978
5979 FormatBackground background;
5980 background.setForegroundColor( convertColor( xf.patternForeColor() ) );
5981 background.setBackgroundColor( convertColor( xf.patternBackColor() ) );
5982 background.setPattern( convertPatternStyle( xf.fillPattern() ) );
5983 format.setBackground( background );
5984
5985 return format;
5986}
5987
5988void ExcelReader::handleXF( XFRecord* record )
5989{
5990 if( !record ) return;
5991
5992 d->xfTable.push_back( *record );
5993}
5994
5995
5996void ExcelReader::mergeTokens( UStringStack* stack, int count, const char* mergeString )
5997{
5998 if( !stack ) return;
5999 if( !stack->size() ) return;
6000 if( count < 1 ) return;
6001
6002 d->mergedTokens.truncate(0);
6003 while(count)
6004 {
6005 count--;
6006
6007 // sanity check
6008 if(stack->size() == 0) break;
6009
6010 d->mergedTokens.prepend((*stack)[ stack->size()-1 ]);
6011 if( count )
6012 d->mergedTokens.prepend(mergeString);
6013 stack->resize( stack->size()-1 );
6014 }
6015
6016 stack->push_back( d->mergedTokens );
6017}
6018
6019void ExcelReader::mergeTokens( UStringStack* stack, int count, const char mergeChar )
6020{
6021 if( !stack ) return;
6022 if( !stack->size() ) return;
6023 if( count < 1 ) return;
6024
6025 d->mergedTokens.truncate(0);
6026 while(count)
6027 {
6028 count--;
6029
6030 // sanity check
6031 if(stack->size() == 0) break;
6032
6033 d->mergedTokens.prepend((*stack)[ stack->size()-1 ]);
6034 if( count )
6035 d->mergedTokens.prepend(mergeChar);
6036 stack->resize( stack->size()-1 );
6037 }
6038
6039 stack->push_back( d->mergedTokens );
6040}
6041
6042#ifdef SWINDER_XLS2RAW
6043void dumpStack( std::vector<UString> stack )
6044{
6045 std::cout << std::endl;
6046 std::cout << "Stack now is: " ;
6047 if( !stack.size() )
6048 std::cout << "(empty)" ;
6049
6050 for( unsigned i = 0; i < stack.size(); i++ )
6051 std::cout << " " << i << ": " << stack[i].ascii() << std::endl;
6052 std::cout << std::endl;
6053}
6054#endif
6055
6056UString ExcelReader::decodeFormula( unsigned row, unsigned col,
6057 const FormulaTokens& tokens, bool openDocumentFormat )
6058{
6059 UStringStack stack;
6060
6061 char argumentSeparator = ',';
6062 if( openDocumentFormat )
6063 argumentSeparator = ';';
6064
6065 for( unsigned c=0; c < tokens.size(); c++ )
6066 {
6067 FormulaToken token = tokens[c];
6068
6069#ifdef SWINDER_XLS2RAW
6070 std::cout << "Token " << c << ": ";
6071 std::cout << token.id() << " ";
6072 std::cout << token.idAsString() << std::endl;
6073#endif
6074
6075 switch( token.id() )
6076 {
6077 case FormulaToken::Add:
6078 mergeTokens( &stack, 2, '+' );
6079 break;
6080
6081 case FormulaToken::Sub:
6082 mergeTokens( &stack, 2, '-' );
6083 break;
6084
6085 case FormulaToken::Mul:
6086 mergeTokens( &stack, 2, '*' );
6087 break;
6088
6089 case FormulaToken::Div:
6090 mergeTokens( &stack, 2, '/' );
6091 break;
6092
6093 case FormulaToken::Power:
6094 mergeTokens( &stack, 2, '^' );
6095 break;
6096
6097 case FormulaToken::Concat:
6098 mergeTokens( &stack, 2, '&' );
6099 break;
6100
6101 case FormulaToken::LT:
6102 mergeTokens( &stack, 2, '<' );
6103 break;
6104
6105 case FormulaToken::LE:
6106 mergeTokens( &stack, 2, "<=" );
6107 break;
6108
6109 case FormulaToken::EQ:
6110 mergeTokens( &stack, 2, '=' );
6111 break;
6112
6113 case FormulaToken::GE:
6114 mergeTokens( &stack, 2, ">=" );
6115 break;
6116
6117 case FormulaToken::GT:
6118 mergeTokens( &stack, 2, '>' );
6119 break;
6120
6121 case FormulaToken::NE:
6122 mergeTokens( &stack, 2, "<>" );
6123 break;
6124
6125 case FormulaToken::Intersect:
6126 mergeTokens( &stack, 2, ' ' );
6127 break;
6128
6129 case FormulaToken::List:
6130 mergeTokens( &stack, 2, ';' );
6131 break;
6132
6133 case FormulaToken::Range:
6134 mergeTokens( &stack, 2, ';' );
6135 break;
6136
6137 case FormulaToken::UPlus:
6138 if(stack.size() > 1)
6139 stack[ stack.size()-1 ].prepend('+');
6140 break;
6141
6142 case FormulaToken::UMinus:
6143 if(stack.size() > 1)
6144 stack[ stack.size()-1 ].prepend('-');
6145 break;
6146
6147 case FormulaToken::Percent:
6148 stack[ stack.size()-1 ].append('%');
6149 break;
6150
6151 case FormulaToken::Paren:
6152 {
6153 UString str(stack[ stack.size()-1 ]);
6154 str.prepend('(');
6155 str.append(')');
6156 stack[ stack.size()-1 ] = str;
6157 }
6158 break;
6159
6160 case FormulaToken::MissArg:
6161 // just ignore
6162 stack.push_back( UString(" ") );
6163 break;
6164
6165 case FormulaToken::String:
6166 {
6167 UString str(token.value().asString());
6168 str.prepend('\"');
6169 str.append('\"');
6170 stack.push_back( str );
6171 }
6172 break;
6173
6174 case FormulaToken::Bool:
6175 if( token.value().asBoolean() )
6176 stack.push_back( UString( "TRUE" ) );
6177 else
6178 stack.push_back( UString( "FALSE" ) );
6179 break;
6180
6181 case FormulaToken::Integer:
6182 stack.push_back( UString::number( token.value().asInteger() ) );
6183 break;
6184
6185 case FormulaToken::Float:
6186 stack.push_back( UString::number( token.value().asFloat() ) );
6187 break;
6188
6189 case FormulaToken::Array:
6190 // FIXME handle this !
6191 break;
6192
6193 case FormulaToken::Ref:
6194 {
6195 UString refName(token.ref( row, col ));
6196 if( openDocumentFormat )
6197 {
6198 refName.prepend('[');
6199 refName.append(']');
6200 }
6201 stack.push_back( refName );
6202 }
6203 break;
6204
6205 case FormulaToken::Ref3d:
6206 {
6207 UString refName("#REF");
6208 refName.reserve(32);
6209
6210 unsigned sheetIndex = token.externSheetRef();
6211 if(sheetIndex < d->sheetRefs.size())
6212 {
6213 UString cellName = token.ref(row, col);
6214 UString sheetName = d->sheetRefs[sheetIndex];
6215
6216 // OpenDocument example: [Sheet1.B1]
6217 if( openDocumentFormat )
6218 {
6219 refName = UString("[");
6220 refName.append( sheetName );
6221 if(!sheetName.isEmpty())
6222 refName.append(UString("."));
6223 refName.append( cellName );
6224 refName.append(UString("]"));
6225 }
6226 else
6227 {
6228 refName = sheetName;
6229 if(!sheetName.isEmpty())
6230 refName.append(UString("."));
6231 refName.append(UString("!"));
6232 refName.append(cellName);
6233 }
6234 }
6235
6236 stack.push_back( refName );
6237 }
6238 break;
6239
6240 case FormulaToken::Area:
6241 {
6242 UString areaName( token.area( row, col ) );
6243 if( openDocumentFormat )
6244 {
6245 areaName.prepend('[');
6246 areaName.append(']');
6247 }
6248 stack.push_back( areaName);
6249 }
6250 break;
6251
6252 case FormulaToken::Area3d:
6253 {
6254 UString areaName("#REF");
6255 areaName.reserve(32);
6256
6257 unsigned sheetIndex = token.externSheetRef();
6258 if(sheetIndex < d->sheetRefs.size())
6259 {
6260 UString rangeName = token.area(row, col);
6261 UString sheetName = d->sheetRefs[sheetIndex];
6262
6263 // OpenDocument example: [Sheet1.B1:B3]
6264 if( openDocumentFormat )
6265 {
6266 areaName = UString("[");
6267 areaName.append( sheetName );
6268 if(!sheetName.isEmpty())
6269 areaName.append('.');
6270 areaName.append( rangeName );
6271 areaName.append(']');
6272 }
6273 else
6274 {
6275 areaName = sheetName;
6276 if(!sheetName.isEmpty())
6277 {
6278 areaName.append('.');
6279 areaName.append('!');
6280 }
6281 areaName.append(rangeName);
6282 }
6283 }
6284 stack.push_back( areaName);
6285 }
6286 break;
6287
6288 case FormulaToken::Function:
6289 {
6290 mergeTokens( &stack, token.functionParams(), argumentSeparator );
6291 if( stack.size() )
6292 {
6293 UString str( token.functionName() ? token.functionName() : "??" );
6294 str.reserve(256);
6295 str.append( '(' );
6296 str.append( stack[ stack.size()-1 ] );
6297 str.append( ')' );
6298 stack[ stack.size()-1 ] = str;
6299 }
6300 }
6301 break;
6302
6303 case FormulaToken::FunctionVar:
6304 if( token.functionIndex() != 255 )
6305 {
6306 mergeTokens( &stack, token.functionParams(), argumentSeparator );
6307 if( stack.size() )
6308 {
6309 UString str;
6310 if( token.functionIndex() != 255 )
6311 str = token.functionName() ? token.functionName() : "??";
6312 str.reserve(256);
6313 str.append( '(' );
6314 str.append( stack[ stack.size()-1 ] );
6315 str.append( ')' );
6316 stack[ stack.size()-1 ] = str;
6317 }
6318 }
6319 else
6320 {
6321 unsigned count = token.functionParams()-1;
6322 mergeTokens( &stack, count, argumentSeparator );
6323 if( stack.size() )
6324 {
6325 UString str;
6326 str.append( '(' );
6327 str.append( stack[ stack.size()-1 ] );
6328 str.append( ')' );
6329 stack[ stack.size()-1 ] = str;
6330 }
6331 }
6332 break;
6333
6334 case FormulaToken::Attr:
6335 if( token.attr() & 0x10 ) // SUM
6336 {
6337 mergeTokens( &stack, 1, argumentSeparator );
6338 if( stack.size() )
6339 {
6340 UString str( "SUM" );
6341 str.append( '(' );
6342 str.append( stack[ stack.size()-1 ] );
6343 str.append( ')' );
6344 stack[ stack.size()-1 ] = str;
6345 }
6346 }
6347 break;
6348
6349 case FormulaToken::NameX:
6350 if( token.nameIndex() > 0 )
6351 if( token.nameIndex() <= d->nameTable.size() )
6352 stack.push_back( d->nameTable[ token.nameIndex()-1 ] );
6353 break;
6354
6355 case FormulaToken::Matrix:
6356 {
6357 int row = token.refRow();
6358 int col = token.refColumn();
6359 //std::cout << "row is " << row << " col is " << col << std::endl;
6360 }
6361 break;
6362
6363 case FormulaToken::NatFormula:
6364 case FormulaToken::Sheet:
6365 case FormulaToken::EndSheet:
6366 case FormulaToken::ErrorCode:
6367 case FormulaToken::Name:
6368 case FormulaToken::MemArea:
6369 case FormulaToken::MemErr:
6370 case FormulaToken::MemNoMem:
6371 case FormulaToken::MemFunc:
6372 case FormulaToken::RefErr:
6373 case FormulaToken::AreaErr:
6374 case FormulaToken::RefN:
6375 case FormulaToken::AreaN:
6376 case FormulaToken::MemAreaN:
6377 case FormulaToken::MemNoMemN:
6378 case FormulaToken::RefErr3d:
6379 case FormulaToken::AreaErr3d:
6380 default:
6381 // FIXME handle this !
6382 stack.push_back( UString("UnknownToken") );
6383 //std::cout << "UnknownToken ID=" << token.id() << std::endl;
6384 break;
6385 };
6386
6387#ifdef SWINDER_XLS2RAW
6388 dumpStack( stack );
6389#endif
6390
6391 }
6392
6393 UString result;
6394 for( unsigned i = 0; i < stack.size(); i++ )
6395 result.append( stack[i] );
6396
6397#ifdef SWINDER_XLS2RAW
6398 std::cout << "FORMULA Result: " << result << std::endl;
6399#endif
6400 return result;
6401}
6402
6403
6404#ifdef SWINDER_XLS2RAW
6405
6406#include <iostream>
6407
6408int main( int argc, char ** argv )
6409{
6410 if( argc < 2 )
6411 {
6412 std::cout << "Usage: xls2raw filename" << std::endl;
6413 return 0;
6414 }
6415
6416 char* filename = argv[1];
6417 std::cout << "Checking " << filename << std::endl;
6418
6419 Workbook* workbook = new Workbook();
6420 ExcelReader* reader = new ExcelReader();
6421 reader->load( workbook, filename );
6422 delete reader;
6423 delete workbook;
6424
6425 return 0;
6426}
6427
6428#endif // XLS2RAW
Beginning of file/set of records.
Definition excel.h:481
static const unsigned int id
Static ID of the BOF record.
Definition excel.h:487
const char * typeAsString() const
Returns BOF type as string, something like "Worksheet".
Definition excel.cpp:1780
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:1796
virtual ~BOFRecord()
Destroys the record.
Definition excel.cpp:1717
unsigned type() const
Returns type of the BOF record, like Workbook, Chart, and so on.
Definition excel.cpp:1764
BOFRecord()
Creates a new BOF record.
Definition excel.cpp:1704
const char * versionAsString() const
Returns the version as string, something like "Excel97".
Definition excel.cpp:1752
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:1722
unsigned version() const
Returns the version, like Excel95, Excel97, and so on.
Definition excel.cpp:1740
Backup upon save.
Definition excel.h:419
BackupRecord()
Creates a new Backup record.
Definition excel.cpp:1624
~BackupRecord()
Destroy the record.
Definition excel.cpp:1631
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:1646
bool backup() const
Returns true if a backup is made when saving the file.
Definition excel.cpp:1636
void setBackup(bool r)
If r is true, a backup will be made when saving the file.
Definition excel.cpp:1641
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:1654
Blank cell.
Definition excel.h:553
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:1678
BlankRecord()
Creates a new Blank record.
Definition excel.cpp:1664
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:1669
Boolean value or error code.
Definition excel.h:586
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:1858
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:1830
BoolErrRecord()
Creates a new BoolErr record.
Definition excel.cpp:1818
static const unsigned int id
Static ID of the BoolErr record.
Definition excel.h:592
Value value() const
Returns value of the cell, could be either boolean or error.
Definition excel.cpp:1853
virtual ~BoolErrRecord()
Destroys the BoolErr record.
Definition excel.cpp:1825
~BottomMarginRecord()
Destroy the record.
Definition excel.cpp:1884
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:1905
double bottomMargin() const
Gets the bottom margin (in inches).
Definition excel.cpp:1889
void setBottomMargin(double m)
Sets the new bottom margin (in inches).
Definition excel.cpp:1894
BottomMarginRecord()
Creates a new BottomMargin record.
Definition excel.cpp:1877
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:1899
Sheet information.
Definition excel.h:692
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:2007
unsigned type() const
Returns the type of the BoundSheet.
Definition excel.cpp:1946
void setBofPosition(unsigned pos)
Sets the position of the BOF record associated with this BoundSheet.
Definition excel.cpp:1992
void setSheetName(const UString &name)
Sets the name of the sheet.
Definition excel.cpp:1982
bool visible() const
Returns true if the sheet is visible.
Definition excel.cpp:1977
virtual const char * name()
Returns the name of the record.
Definition excel.h:767
virtual ~BoundSheetRecord()
Destroys the BoundSheet record.
Definition excel.cpp:2002
UString sheetName() const
Returns the name of the sheet.
Definition excel.cpp:1987
BoundSheetRecord()
Creates a new BoundSheet record.
Definition excel.cpp:1926
const char * typeAsString() const
Returns the type of the BoundSheet as string.
Definition excel.cpp:1959
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:2027
void setVisible(bool visible)
Sets the visibility of the sheet.
Definition excel.cpp:1972
void setType(unsigned type)
Sets the type of the BoundSheet.
Definition excel.cpp:1935
unsigned bofPosition() const
Returns the position of the BOF record associated with this BoundSheet.
Definition excel.cpp:1997
Automatic recalculation mode.
Definition excel.h:787
~CalcModeRecord()
Destroy the record.
Definition excel.cpp:2054
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:2069
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:2077
void setAutoCalc(bool r)
If r is true, formulas calculation will be performed automatically.
Definition excel.cpp:2064
bool autoCalc() const
Returns true if formulas calculation is performed automatically.
Definition excel.cpp:2059
CalcModeRecord()
Creates a new CalcMode record.
Definition excel.cpp:2047
virtual void setXfIndex(unsigned i)
Sets the XF index for formatting of the cell.
Definition excel.cpp:1412
virtual void setColumn(unsigned c)
Sets the column associated with the cell information.
Definition excel.cpp:1402
virtual unsigned xfIndex() const
Returns the XF index for formatting of the cell.
Definition excel.cpp:1407
virtual void setRow(unsigned r)
Sets the row associated with the cell information.
Definition excel.cpp:1392
virtual unsigned row() const
Returns the row associated with the cell information.
Definition excel.cpp:1387
virtual unsigned column() const
Returns the column associated with the cell information.
Definition excel.cpp:1397
CellInfo()
Creates a new cell information.
Definition excel.cpp:1374
virtual ~CellInfo()
Destroys the cell information.
Definition excel.cpp:1382
Columns width and format.
Definition excel.h:842
unsigned outlineLevel() const
Returns the outline level of the columns.
Definition excel.cpp:2154
unsigned xfIndex() const
Returns the XF index for the formatting of the column(s).
Definition excel.cpp:2124
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:2179
virtual ~ColInfoRecord()
Destroys the record.
Definition excel.cpp:2108
void setOutlineLevel(unsigned l)
Sets the outline level of the columns.
Definition excel.cpp:2159
ColInfoRecord()
Creates a new ColInfo record.
Definition excel.cpp:2097
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:2164
void setXfIndex(unsigned i)
Sets the XF index for the formatting of the column(s).
Definition excel.cpp:2129
void setHidden(bool h)
Sets whether columns should be hidden or visible.
Definition excel.cpp:2139
bool collapsed() const
Returns true if the columns should be collapsed.
Definition excel.cpp:2144
bool hidden() const
Returns true if the columns should be hidden, i.e not visible.
Definition excel.cpp:2134
void setWidth(unsigned w)
Sets the width of the column(s), specified in 1/256 of a character width.
Definition excel.cpp:2119
unsigned width() const
Returns the width of the column(s), specified in 1/256 of a character width.
Definition excel.cpp:2114
void setCollapsed(bool c)
Sets whether columns should be collapsed or not.
Definition excel.cpp:2149
Provides color based on RGB values.
virtual unsigned lastColumn() const
Returns the last column associated with the span information.
Definition excel.cpp:1450
virtual void setLastColumn(unsigned c)
Sets the last column associated with the span information.
Definition excel.cpp:1455
virtual unsigned firstColumn() const
Returns the first column associated with the span information.
Definition excel.cpp:1440
virtual ~ColumnSpanInfo()
Destroys the column span information.
Definition excel.cpp:1435
ColumnSpanInfo()
Creates a new column span information.
Definition excel.cpp:1428
virtual void setFirstColumn(unsigned c)
Sets the first column associated with the span information.
Definition excel.cpp:1445
Date reference.
Definition excel.h:963
~DateModeRecord()
Destroy the record.
Definition excel.cpp:2208
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:2223
DateModeRecord()
Creates a new DateMode record.
Definition excel.cpp:2201
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:2231
bool base1904() const
Returns true if the reference date is 1st of January, 1904 or false if the reference date is 31st of ...
Definition excel.cpp:2213
void setBase1904(bool r)
If r is true, sets the reference date to 1st of January, 1904.
Definition excel.cpp:2218
Range of used area.
Definition excel.h:1020
void setFirstColumn(unsigned r)
Sets index to the first used column.
Definition excel.cpp:2291
void setFirstRow(unsigned r)
Sets index to the first used row.
Definition excel.cpp:2271
DimensionRecord()
Creates a new Dimension record.
Definition excel.cpp:2251
unsigned firstColumn() const
Returns index to the first used column.
Definition excel.cpp:2286
unsigned lastColumn() const
Returns index to the last used column.
Definition excel.cpp:2296
void setLastColumn(unsigned r)
Sets index to the last used column.
Definition excel.cpp:2301
unsigned lastRow() const
Returns index to the last used row.
Definition excel.cpp:2276
unsigned firstRow() const
Returns index to the first used row.
Definition excel.cpp:2266
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:2316
void setLastRow(unsigned r)
Sets index to the last used row.
Definition excel.cpp:2281
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:2306
~DimensionRecord()
Destroys the record.
Definition excel.cpp:2261
End of record set.
Definition excel.h:1199
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:2338
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:2343
virtual ~EOFRecord()
Destroy the record.
Definition excel.cpp:2334
EOFRecord()
Creates a new EOF record.
Definition excel.cpp:2329
Font information.
Definition excel.h:1277
bool italic() const
Returns true if italic has been set.
Definition excel.cpp:2667
void setColorIndex(unsigned c)
Sets the index of the color of the font.
Definition excel.cpp:2652
void setEscapement(unsigned s)
Sets the superscript or subscript.
Definition excel.cpp:2692
FontRecord & operator=(const FontRecord &fr)
Assigns from another Font record.
Definition excel.cpp:2592
virtual ~FontRecord()
Destroy the record.
Definition excel.cpp:2581
void setItalic(bool i)
If i is true, italic is set on; otherwise italic is set off.
Definition excel.cpp:2672
UString fontName() const
Returns the name of font, e.g "Arial".
Definition excel.cpp:2617
bool strikeout() const
Returns true if strikeout has been set.
Definition excel.cpp:2677
void setFontName(const UString &fn)
Sets the name of the font.
Definition excel.cpp:2622
void setBoldness(unsigned b)
Sets the boldness of the font.
Definition excel.cpp:2662
void setStrikeout(bool s)
If s is true, strikeout is set on; otherwise strikeout is set off.
Definition excel.cpp:2682
void setUnderline(unsigned u)
Sets the underline style of the font.
Definition excel.cpp:2702
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:2734
FontRecord()
Creates a new Font record.
Definition excel.cpp:2566
unsigned underline() const
Returns the underline style of the font.
Definition excel.cpp:2697
unsigned escapement() const
Returns Font::Superscript if superscript is set, or Font::Subscript if subscript is set,...
Definition excel.cpp:2687
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:2708
unsigned colorIndex() const
Returns index of the color of the font.
Definition excel.cpp:2647
unsigned boldness() const
Returns the boldness of the font.
Definition excel.cpp:2657
Sheet footer.
Definition excel.h:1453
void setFooter(const UString &f)
Sets the footer.
Definition excel.cpp:2779
~FooterRecord()
Destroy the record.
Definition excel.cpp:2769
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:2794
FooterRecord()
Creates a new Footer record.
Definition excel.cpp:2763
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:2784
UString footer() const
Gets the footer.
Definition excel.cpp:2774
void setForegroundColor(const Color &)
Sets the foreground color.
void setBackgroundColor(const Color &)
Set the background color.
void setPattern(unsigned)
Set the pattern for this background.
void setRightBorder(const Pen &pen)
Sets pen style, width and color for right border.
void setTopBorder(const Pen &pen)
Sets pen style, width and color for top border.
void setLeftBorder(const Pen &pen)
Sets pen style, width and color for left border.
void setBottomBorder(const Pen &pen)
Sets pen style, width and color for bottom border.
Defines font information for cell format.
bool isNull() const
Returns true if it is a default font information.
void setColor(const Color &color)
Sets the color of the font.
void setFontFamily(const UString &fontFamily)
Sets a new family for the font information.
void setStrikeout(bool s)
If s is true, strikeout is set on; otherwise strikeout is set off.
void setFontSize(double fs)
Sets the size of font (in points).
void setSuperscript(bool s)
If s is true, superscript is set on; otherwise superscript is set off.
void setSubscript(bool s)
If s is true, subscript is set on; otherwise subscript is set off.
void setBold(bool b)
If b is true, bold is set on; otherwise bold is set off.
void setUnderline(bool u)
If u is true, underline is set on; otherwise underline is set off.
void setItalic(bool i)
If i is true, italic is set on; otherwise italic is set off.
Number formatting string.
Definition excel.h:1509
void setFormatString(const UString &fs)
Sets the formatting string of the format.
Definition excel.cpp:2852
UString formatString() const
Returns the formatting string of the format, e.g "0.00" for 2 decimal places number formatting.
Definition excel.cpp:2847
FormatRecord & operator=(const FormatRecord &fr)
Assigns from another Format record.
Definition excel.cpp:2830
void setIndex(unsigned i)
Sets the index of the format.
Definition excel.cpp:2842
~FormatRecord()
Destroys the Format record.
Definition excel.cpp:2818
unsigned index() const
Returns the index of the format.
Definition excel.cpp:2837
FormatRecord()
Creates a new Format record.
Definition excel.cpp:2811
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:2869
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:2857
void setBackground(const FormatBackground &)
Sets new background information for this format.
void setFont(const FormatFont &font)
Sets new font information for this format.
void setValueFormat(const UString &valueFormat)
Sets the new formatting string to display the value of this format.
void setAlignment(const FormatAlignment &alignment)
Sets new alignment information for this format.
void setBorders(const FormatBorders &border)
Sets new borders information for this format.
Value result() const
Gets the result of the formula.
Definition excel.cpp:2900
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:2987
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:2915
~FormulaRecord()
Destroy the record.
Definition excel.cpp:2895
void setResult(const Value &v)
Sets the result of the formula.
Definition excel.cpp:2905
FormulaRecord()
Creates a new formula record.
Definition excel.cpp:2889
Sheet header.
Definition excel.h:1641
~HeaderRecord()
Destroy the record.
Definition excel.cpp:3073
HeaderRecord()
Creates a new Header record.
Definition excel.cpp:3067
void setHeader(const UString &h)
Sets the header.
Definition excel.cpp:3083
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3088
UString header() const
Gets the header.
Definition excel.cpp:3078
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3098
Class LabelRecord represents a cell that contains a string.
Definition excel.h:1696
void setLabel(const UString &l)
Sets the label string.
Definition excel.cpp:3029
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3048
LabelRecord()
Creates a new Label record.
Definition excel.cpp:3012
UString label() const
Returns the label string.
Definition excel.cpp:3024
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3034
virtual ~LabelRecord()
Destroys the record.
Definition excel.cpp:3019
Class LabelSSTRecord represents a cell that contains a string.
Definition excel.h:1750
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3131
unsigned sstIndex() const
Returns the SST index.
Definition excel.cpp:3126
virtual ~LabelSSTRecord()
Destroys the record.
Definition excel.cpp:3121
LabelSSTRecord()
Creates a new LabelSST record.
Definition excel.cpp:3114
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3142
Class LeftMarginRecord holds information about left margin.
Definition excel.h:1795
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3183
~LeftMarginRecord()
Destroy the record.
Definition excel.cpp:3168
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3189
double leftMargin() const
Gets the left margin (in inches).
Definition excel.cpp:3173
void setLeftMargin(double m)
Sets the new left margin (in inches).
Definition excel.cpp:3178
LeftMarginRecord()
Creates a new LeftMargin record.
Definition excel.cpp:3161
Class MergedCellsRecord represents MergedCells record, which contains a list of all merged cells in t...
Definition excel.h:1848
unsigned firstColumn(unsigned i) const
Returns the index to first column in the i-th position in the list.
Definition excel.cpp:3241
virtual ~MergedCellsRecord()
Destroys the record.
Definition excel.cpp:3217
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3255
unsigned count() const
Returns the total number of merged cells in the list.
Definition excel.cpp:3222
unsigned firstRow(unsigned i) const
Returns the index to first row in the i-th position in the list.
Definition excel.cpp:3227
unsigned lastColumn(unsigned i) const
Returns the index to last column in the i-th position in the list.
Definition excel.cpp:3248
unsigned lastRow(unsigned i) const
Returns the index to last row in the i-th position in the list.
Definition excel.cpp:3234
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3277
MergedCellsRecord()
Creates a new MergedCells record.
Definition excel.cpp:3211
Class MulBlankRecord represents a cell range containing blank cells.
Definition excel.h:1915
unsigned xfIndex(unsigned i) const
Returns XF index of ith column.
Definition excel.cpp:3327
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3311
MulBlankRecord()
Creates a new MulBlank record.
Definition excel.cpp:3300
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3333
virtual ~MulBlankRecord()
Destroys the record.
Definition excel.cpp:3306
Class MulRKRecord represents a cell range containing RK value cells.
Definition excel.h:1967
MulRKRecord()
Creates a new MulRK record.
Definition excel.cpp:3355
virtual ~MulRKRecord()
Destroys the record.
Definition excel.cpp:3361
double asFloat(unsigned i) const
Returns the floating-point value specified by the record.
Definition excel.cpp:3384
bool isInteger(unsigned i) const
Returns true if the record holds an integer value.
Definition excel.cpp:3372
int asInteger(unsigned i) const
Returns the integer value specified by the record.
Definition excel.cpp:3378
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3425
unsigned xfIndex(unsigned i) const
Returns XF index of ith column.
Definition excel.cpp:3366
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3396
Class NumberRecord represents a cell that contains a floating point value.
Definition excel.h:2076
double number() const
Returns the floating-point value specified by the record.
Definition excel.cpp:3526
void setNumber(double f)
Sets the floating-point value specified by the record.
Definition excel.cpp:3531
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3537
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3547
NumberRecord()
Creates a new Number record.
Definition excel.cpp:3514
virtual ~NumberRecord()
Destroys the record.
Definition excel.cpp:3521
Class PaletteRecord lists colors.
Definition excel.h:2129
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3603
unsigned count() const
Returns the number of colors in the palette.
Definition excel.cpp:3582
PaletteRecord()
Creates a new Palette record.
Definition excel.cpp:3566
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3587
~PaletteRecord()
Destroy the record.
Definition excel.cpp:3572
Color color(unsigned i) const
Gets the n-th color.
Definition excel.cpp:3577
Class RKRecord represents a cell that contains an RK value, i.e encoded integer or floating-point val...
Definition excel.h:2232
bool isInteger() const
Returns true if the record holds an integer value.
Definition excel.cpp:3689
bool isFloat() const
Returns true if the record holds a floating-point value.
Definition excel.cpp:3694
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3736
RKRecord()
Creates a new RK record.
Definition excel.cpp:3674
virtual ~RKRecord()
Destroys the record.
Definition excel.cpp:3684
void setFloat(double f)
Sets the floating-point value to be specified by the record.
Definition excel.cpp:3722
void setInteger(int i)
Sets the integer value to be specified by the record.
Definition excel.cpp:3715
int asInteger() const
Returns the integer value specified by the record.
Definition excel.cpp:3699
double asFloat() const
Returns the floating-point value specified by the record.
Definition excel.cpp:3707
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3751
Class RStringRecord represents a cell that contains rich-text string.
Definition excel.h:2419
UString label() const
Returns the label string.
Definition excel.cpp:3877
void setLabel(const UString &l)
Sets the label string.
Definition excel.cpp:3882
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3903
RStringRecord()
Creates a new Label record.
Definition excel.cpp:3865
virtual ~RStringRecord()
Destroys the record.
Definition excel.cpp:3872
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3888
Class Record represents a base class for all other type record, hence do not use this class in real l...
Definition excel.h:205
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:1609
static const unsigned int id
Static ID of the record.
Definition excel.h:212
unsigned position() const
Gets the position of this record in the OLE stream.
Definition excel.cpp:1600
static Record * create(unsigned type)
Record factory, create a new record of specified type.
Definition excel.cpp:1474
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:1605
void setPosition(unsigned pos)
Sets the position of the record in the OLE stream.
Definition excel.cpp:1595
virtual ~Record()
Destroys the record.
Definition excel.cpp:1470
Record()
Creates a new generic record.
Definition excel.cpp:1464
Class RightMarginRecord holds information about right margin.
Definition excel.h:2180
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3655
double rightMargin() const
Gets the right margin (in inches).
Definition excel.cpp:3639
void setRightMargin(double m)
Sets the new right margin (in inches).
Definition excel.cpp:3644
RightMarginRecord()
Creates a new RightMargin record.
Definition excel.cpp:3627
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3649
~RightMarginRecord()
Destroy the record.
Definition excel.cpp:3634
Class RowRecord represents Row record, which provides information (such as row height and formatting)...
Definition excel.h:2317
unsigned row() const
Returns the index of the row.
Definition excel.cpp:3790
virtual ~RowRecord()
Destroys the record.
Definition excel.cpp:3785
void setRow(unsigned r)
Sets the index of the row.
Definition excel.cpp:3795
unsigned height() const
Returns the height of the row, specified in twips (1/20 pt).
Definition excel.cpp:3800
void setXfIndex(unsigned i)
Sets the XF index for the formatting of the cells.
Definition excel.cpp:3815
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3844
bool hidden() const
Returns true if the row should be hidden, i.e not visible.
Definition excel.cpp:3820
void setHeight(unsigned h)
Sets the height of the row, specified in twips (1/20 pt).
Definition excel.cpp:3805
RowRecord()
Creates a new Row record.
Definition excel.cpp:3775
void setHidden(bool h)
Sets whether row should be hidden or visible.
Definition excel.cpp:3825
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3830
unsigned xfIndex() const
Returns the XF index for the formatting of the cells.
Definition excel.cpp:3810
Class SSTRecord represents SST record, which holds the shared string table of the workbook.
Definition excel.h:2476
SSTRecord()
Creates a new SST record.
Definition excel.cpp:3924
virtual ~SSTRecord()
Destroys the record.
Definition excel.cpp:3932
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:3995
unsigned count() const
Returns the number of available string in this string table.
Definition excel.cpp:3983
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:3947
UString stringAt(unsigned index) const
Returns the string at specified index.
Definition excel.cpp:3989
Class String represents a string record, which holds the value of calculation if a formula returns a ...
Definition excel.h:2532
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:4046
UString ustring() const
Returns the string (in Unicode).
Definition excel.cpp:4036
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:4026
StringRecord()
Creates a new string record.
Definition excel.cpp:4015
virtual ~StringRecord()
Destroys the record.
Definition excel.cpp:4021
Value value() const
Returns the string as a value.
Definition excel.cpp:4041
Class SupbookRecord stores references to external workbook.
Definition excel.h:2579
ReferenceType referenceType() const
Returns the type of the reference.
Definition excel.cpp:4073
SupbookRecord()
Creates a new Supbook record.
Definition excel.cpp:4062
void setReferenceType(ReferenceType type)
Sets the type of the reference.
Definition excel.cpp:4078
~SupbookRecord()
Destroy the record.
Definition excel.cpp:4068
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:4117
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:4083
Class TopMarginRecord holds information about top margin.
Definition excel.h:2637
void setTopMargin(double m)
Sets the new top margin (in inches).
Definition excel.cpp:4150
double topMargin() const
Gets the top margin (in inches).
Definition excel.cpp:4145
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:4161
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:4155
TopMarginRecord()
Creates a new TopMargin record.
Definition excel.cpp:4133
~TopMarginRecord()
Destroy the record.
Definition excel.cpp:4140
UString & prepend(const UString &)
Prepend another string.
int find(const UString &f, int pos=0) const
static UString number(int i)
Constructs a string from an int.
char * ascii() const
Convert the Unicode string to plain ASCII chars chopping of any higher bytes.
static UString null
Static instance of a null string.
UString substr(int pos=0, int len=-1) const
void reserve(int r)
Reserves room for the string, useful to speed up append().
UString & append(const UString &)
Append another string.
Provides a wrapper for cell value.
Definition value.h:43
static const Value & empty()
Returns constant reference to empty value.
Definition value.cpp:278
static const Value & errorDIV0()
Returns constant reference to DIV/0!
Definition value.cpp:284
static const Value & errorNULL()
Returns constant reference to NULL!
Definition value.cpp:316
static const Value & errorNAME()
Returns constant reference to NAME?
Definition value.cpp:300
static const Value & errorNUM()
Returns constant reference to NUM!
Definition value.cpp:308
static const Value & errorREF()
Returns constant reference to REF!
Definition value.cpp:324
double asFloat() const
Returns the floating-point value of this value.
Definition value.cpp:226
UString asString() const
Returns the string value of this value.
Definition value.cpp:248
bool isString() const
Returns true if the type of this value is string.
Definition value.h:145
static const Value & errorVALUE()
Returns constant reference to VALUE!
Definition value.cpp:332
bool asBoolean() const
Returns the boolean value of this value.
Definition value.cpp:180
static const Value & errorNA()
Returns constant reference to N/A error.
Definition value.cpp:292
int asInteger() const
Returns the integer value of this value.
Definition value.cpp:199
Class XFRecord holds information of XF (eXtended Format) which specifies many kind of properties of a...
Definition excel.h:2688
unsigned indentLevel() const
Returns indent level.
Definition excel.cpp:4409
void setPatternForeColor(unsigned color)
Sets the fill foreground color.
Definition excel.cpp:4564
bool formulaHidden() const
Returns true if the formula of the cells using this format should be hidden from user.
Definition excel.cpp:4308
void setRotationAngle(unsigned angle)
Sets the rotation angle of the text.
Definition excel.cpp:4394
virtual void dump(std::ostream &out) const
Dumps record information to output stream.
Definition excel.cpp:4657
unsigned topBorderColor() const
Returns the color for top border.
Definition excel.cpp:4479
unsigned horizontalAlignment() const
Gets the horizontal alignment, e.g Left.
Definition excel.cpp:4328
unsigned leftBorderStyle() const
Returns the line style for left border.
Definition excel.cpp:4429
void setTopBorderColor(unsigned color)
Sets the color for top border.
Definition excel.cpp:4484
XFRecord & operator=(const XFRecord &xf)
Assigns from another XF record.
Definition excel.cpp:4246
void setLeftBorderColor(unsigned color)
Sets the color for left border.
Definition excel.cpp:4444
const char * horizontalAlignmentAsString() const
Returns human-readable string representation of the horizontal alignment.
Definition excel.cpp:4338
void setFormatIndex(unsigned fi)
Sets the index of the number format for use in this XFormat.
Definition excel.cpp:4293
void setPatternBackColor(unsigned color)
Sets the fill background color.
Definition excel.cpp:4574
unsigned parentStyle() const
Returns the index of the parent stlye of this format.
Definition excel.cpp:4318
unsigned fontIndex() const
Gets the index of the font for use in this XFormat.
Definition excel.cpp:4278
unsigned rightBorderStyle() const
Returns the line style for right border.
Definition excel.cpp:4449
void setShrinkContent(bool s)
Sets whether content should be shrunk to fit into cell.
Definition excel.cpp:4424
bool textWrap() const
Returns true if text is wrapped at right border.
Definition excel.cpp:4379
void setLocked(bool l)
Sets whether the cells using this format should be locked or not.
Definition excel.cpp:4303
void setTextWrap(bool wrap)
Sets whether text should be wrapped at right border.
Definition excel.cpp:4384
void setFormulaHidden(bool f)
Sets whether the formula of the cells using this format should be hidden or should be visible.
Definition excel.cpp:4313
unsigned patternBackColor() const
Returns the fill background color.
Definition excel.cpp:4569
void setVerticalAlignment(unsigned va)
Sets the vertical alignment, e.g Top.
Definition excel.cpp:4359
unsigned rightBorderColor() const
Returns the color for right border.
Definition excel.cpp:4459
void setStackedLetters(bool stacked)
Sets whether the letters for text should be stacked top-to-bottom.
Definition excel.cpp:4404
void setDiagonalTopLeft(bool d)
Sets whether there should be a diagonal line from top left to right bottom.
Definition excel.cpp:4514
unsigned patternForeColor() const
Returns the fill foreground color.
Definition excel.cpp:4559
unsigned verticalAlignment() const
Gets the vertical alignment, e.g Bottom.
Definition excel.cpp:4354
bool stackedLetters() const
Returns true if the letters for text are not rotated, but instead stacked top-to-bottom.
Definition excel.cpp:4399
~XFRecord()
Destroy the record.
Definition excel.cpp:4235
void setParentStyle(unsigned ps)
Sets the index of the parent stlye of this format.
Definition excel.cpp:4323
unsigned bottomBorderStyle() const
Returns the line style for bottom border.
Definition excel.cpp:4489
bool diagonalBottomLeft() const
Returns true if there is a diagonal line from bottom left to right top.
Definition excel.cpp:4519
void setRightBorderStyle(unsigned style)
Sets the line style for right border.
Definition excel.cpp:4454
unsigned diagonalColor() const
Returns the color for diagonal line.
Definition excel.cpp:4539
unsigned diagonalStyle() const
Returns the diagonal line style.
Definition excel.cpp:4529
const char * verticalAlignmentAsString() const
Returns human-readable string representation of the vertical alignment.
Definition excel.cpp:4364
void setLeftBorderStyle(unsigned style)
Sets the line style for left border.
Definition excel.cpp:4434
void setBottomBorderStyle(unsigned style)
Sets the line style for bottom border.
Definition excel.cpp:4494
unsigned bottomBorderColor() const
Returns the color for bottom border.
Definition excel.cpp:4499
void setDiagonalColor(unsigned color)
Sets the color for diagonal line.
Definition excel.cpp:4544
unsigned fillPattern() const
Returns fill pattern.
Definition excel.cpp:4549
void setFontIndex(unsigned fi)
Sets the index of the font for use in this XFormat.
Definition excel.cpp:4283
void setIndentLevel(unsigned i)
Sets indent level.
Definition excel.cpp:4414
unsigned leftBorderColor() const
Returns the color for left border.
Definition excel.cpp:4439
unsigned formatIndex() const
Gets the index of the number format for use in this XFormat.
Definition excel.cpp:4288
void setDiagonalStyle(unsigned style)
Sets the line style for diagonal line.
Definition excel.cpp:4534
void setRightBorderColor(unsigned color)
Sets the color for right border.
Definition excel.cpp:4464
unsigned topBorderStyle() const
Returns the line style for top border.
Definition excel.cpp:4469
XFRecord()
Creates a new XF record.
Definition excel.cpp:4203
unsigned rotationAngle() const
Returns the rotation angle of the text.
Definition excel.cpp:4389
virtual void setData(unsigned size, const unsigned char *data)
Sets the data for this record.
Definition excel.cpp:4579
bool shrinkContent() const
Returns true if content should be shrunk to fit into cell.
Definition excel.cpp:4419
void setFillPattern(unsigned pattern)
Sets fill pattern.
Definition excel.cpp:4554
void setBottomBorderColor(unsigned color)
Sets the color for bottom border.
Definition excel.cpp:4504
void setHorizontalAlignment(unsigned ha)
Sets the horizontal alignment, e.g Left.
Definition excel.cpp:4333
void setTopBorderStyle(unsigned style)
Sets the line style for top border.
Definition excel.cpp:4474
void setDiagonalBottomLeft(bool d)
Sets whether there should be a diagonal line from bottom left to right top.
Definition excel.cpp:4524
bool locked() const
Returns true if the cells using this format should be locked.
Definition excel.cpp:4298
bool diagonalTopLeft() const
Returns true if there is a diagonal line from top left to right bottom.
Definition excel.cpp:4509