filters

excel.cpp

00001 /* Swinder - Portable library for spreadsheet
00002    Copyright (C) 2003-2005 Ariya Hidayat <ariya@kde.org>
00003    Copyright (C) 2006 Marijn Kruisselbrink <m.kruisselbrink@student.tue.nl>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA
00019 */
00020 
00021 #include "excel.h"
00022 
00023 #include <iostream>
00024 #include <iomanip>
00025 #include <vector>
00026 #include <string>
00027 #include <map>
00028 #include <stdio.h> // memcpy
00029 
00030 #include "pole.h"
00031 #include "swinder.h"
00032 
00033 // Use anonymous namespace to cover following functions
00034 namespace{
00035 
00036 static inline unsigned long readU16( const void* p )
00037 {
00038   const unsigned char* ptr = (const unsigned char*) p;
00039   return ptr[0]+(ptr[1]<<8);
00040 }
00041 
00042 static inline unsigned long readU32( const void* p )
00043 {
00044   const unsigned char* ptr = (const unsigned char*) p;
00045   return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24);
00046 }
00047 
00048 typedef double& data_64;
00049 inline void convert_64 (data_64 convert)
00050 {
00051   register unsigned char temp;
00052   register unsigned int u_int_temp;
00053   temp = ((unsigned char*)&convert)[0];
00054   ((unsigned char*)&convert)[0] = ((unsigned char*)&convert)[3];
00055   ((unsigned char*)&convert)[3] = temp;
00056   temp = ((unsigned char*)&convert)[1];
00057   ((unsigned char*)&convert)[1] = ((unsigned char*)&convert)[2];
00058   ((unsigned char*)&convert)[2] = temp;
00059   temp = ((unsigned char*)&convert)[4];
00060   ((unsigned char*)&convert)[4] = ((unsigned char*)&convert)[7];
00061   ((unsigned char*)&convert)[7] = temp;
00062   temp = ((unsigned char*)&convert)[5];
00063   ((unsigned char*)&convert)[5] = ((unsigned char*)&convert)[6];
00064   ((unsigned char*)&convert)[6] = temp;
00065        
00066   u_int_temp = ((unsigned int *)&convert)[0];
00067   ((unsigned int *)&convert)[0] = ((unsigned int *)&convert)[1];
00068   ((unsigned int *)&convert)[1] = u_int_temp;
00069 }
00070 
00071 inline bool isLittleEndian(void)
00072 {
00073   long i = 0x44332211;
00074   unsigned char* a = (unsigned char*) &i;
00075   return ( *a == 0x11 );
00076 }
00077 
00078 
00079 // FIXME check that double is 64 bits
00080 static inline double readFloat64( const void*p )
00081 {
00082   const double* ptr = (const double*) p;
00083   double num = 0.0;
00084   num = *ptr;
00085  
00086   if( !isLittleEndian() )
00087     convert_64( num );
00088     
00089   return num;
00090 }
00091 
00092 // RK value is special encoded integer or floating-point
00093 // see any documentation of Excel file format for detail description
00094 static inline void decodeRK( unsigned rkvalue, bool& isInteger,
00095   int& i, double& f )
00096 {
00097   double factor = (rkvalue & 0x01) ? 0.01 : 1;
00098   if( rkvalue & 0x02 )
00099   {
00100     // FIXME check that int is 32 bits ?
00101     isInteger = true;
00102     i = (int)(factor * (*((int*) &rkvalue) >> 2) );
00103   }
00104   else
00105   {
00106     // TODO ensure double takes 8 bytes
00107     isInteger = false;
00108     unsigned char* s = (unsigned char*) &rkvalue;
00109     unsigned char* r = (unsigned char*) &f;
00110     if( isLittleEndian() )
00111     {
00112       r[0] = r[1] = r[2] = r[3] = 0;
00113       r[4] = s[0] & 0xfc;
00114       r[5] = s[1]; r[6] = s[2];  r[7] = s[3];
00115     }
00116     else
00117     {    
00118       r[0] = r[1] = r[2] = r[3] = 0;
00119       r[4] = s[0] & 0xfc;
00120       r[5] = s[1]; r[6] = s[2];  r[7] = s[3];
00121     }  
00122     memcpy( &f, r, 8 );
00123     f *= factor;
00124   }
00125 }
00126 
00127 }
00128 
00129 namespace Swinder 
00130 {
00131 std::ostream& operator<<( std::ostream& s, Swinder::UString ustring )
00132 {
00133   char* str = ustring.ascii();
00134   s << str;
00135   return s;
00136 }
00137 
00138 }
00139 
00140 using namespace Swinder;
00141 
00142 static Value errorAsValue( int errorCode )
00143 {
00144   Value result( Value::Error );
00145   
00146   switch( errorCode )
00147   {
00148     case 0x00: result = Value::errorNULL();  break;
00149     case 0x07: result = Value::errorDIV0();  break;
00150     case 0x0f: result = Value::errorVALUE(); break;
00151     case 0x17: result = Value::errorREF();   break;
00152     case 0x1d: result = Value::errorNAME();  break;
00153     case 0x24: result = Value::errorNUM();   break;
00154     case 0x2A: result = Value::errorNA();    break;
00155     default: break;
00156   };
00157   
00158   return result;
00159 }
00160 
00161 //=============================================
00162 //          EString
00163 //=============================================
00164 
00165 
00166 class EString::Private
00167 {
00168 public:
00169   bool unicode;
00170   bool richText;
00171   UString str;
00172   unsigned size;
00173 };
00174 
00175 EString::EString()
00176 {
00177   d = new EString::Private();
00178   d->unicode  = false;
00179   d->richText = false;
00180   d->str      = UString::null;
00181   d->size     = 0;
00182 }
00183 
00184 EString::EString( const EString& es )
00185 {
00186   d = new EString::Private();
00187   operator=( es );
00188 }
00189 
00190 EString& EString::operator=( const EString& es )
00191 {
00192   d->unicode  = es.d->unicode;
00193   d->richText = es.d->richText;
00194   d->size     = es.d->size;
00195   d->str      = es.d->str;
00196   return *this;
00197 }
00198 
00199 EString::~EString()
00200 {
00201   delete d;
00202 }
00203 
00204 bool EString::unicode() const
00205 {
00206   return d->unicode;
00207 }
00208 
00209 void EString::setUnicode( bool u )
00210 {
00211   d->unicode = u;
00212 }
00213 
00214 bool EString::richText() const
00215 {
00216   return d->richText;
00217 }
00218 
00219 void EString::setRichText( bool r )
00220 {
00221   d->richText = r;
00222 }
00223 
00224 UString EString::str() const
00225 {
00226   return d->str;
00227 }
00228 
00229 void EString::setStr( const UString& str )
00230 {
00231   d->str = str;
00232 }
00233 
00234 unsigned EString::size() const
00235 {
00236   return d->size;
00237 }
00238 
00239 void EString::setSize( unsigned s )
00240 {
00241   d->size = s;
00242 }
00243 
00244 // FIXME use maxsize for sanity check
00245 EString EString::fromUnicodeString( const void* p, bool longString, unsigned /* maxsize */ )
00246 {
00247   const unsigned char* data = (const unsigned char*) p;
00248   UString str = UString::null;
00249   
00250   unsigned offset = longString ? 2 : 1;  
00251   unsigned len = longString ? readU16( data  ): data[0];
00252   unsigned char flag = data[ offset ];
00253   offset++; // for flag (1 byte)
00254   
00255   bool unicode = flag & 0x01;
00256   bool richText = flag & 0x08;
00257   unsigned formatRuns = 0;
00258   
00259   if( richText )
00260   {
00261     formatRuns = readU16( data + offset );
00262     offset += 2;
00263   }
00264   
00265   // find out total bytes used in this string
00266   unsigned size = offset + len; // string data
00267   if( unicode ) size += len; // because unicode takes 2-bytes char
00268   if( richText ) size += (formatRuns*4);
00269   
00270   if( !unicode )
00271   {
00272     char* buffer = new char[ len+1 ];
00273     memcpy( buffer, data + offset, len );
00274     buffer[ len ] = 0;
00275     str = UString( buffer );
00276     delete[] buffer;
00277   }
00278   else
00279   {
00280     str = UString();
00281     for( unsigned k=0; k<len; k++ )
00282     {
00283       unsigned uchar = readU16( data + offset + k*2 );
00284       str.append( UString(UChar(uchar)) );
00285     }
00286   }
00287   
00288   EString result;
00289   result.setUnicode( unicode );
00290   result.setRichText( richText );
00291   result.setSize( size );
00292   result.setStr( str );
00293   
00294   return result;
00295 }
00296 
00297 // FIXME use maxsize for sanity check
00298 EString EString::fromByteString( const void* p, bool longString, 
00299   unsigned /* maxsize */ )
00300 {
00301   const unsigned char* data = (const unsigned char*) p;
00302   UString str = UString::null;
00303   
00304   unsigned offset = longString ? 2 : 1;  
00305   unsigned len = longString ? readU16( data  ): data[0];
00306   
00307   char* buffer = new char[ len+1 ];
00308   memcpy( buffer, data + offset, len );
00309   buffer[ len ] = 0;
00310   str = UString( buffer );
00311   delete[] buffer;
00312   
00313   unsigned size = offset + len;
00314   
00315   EString result;
00316   result.setUnicode( false );
00317   result.setRichText( false );
00318   result.setSize( size );
00319   result.setStr( str );
00320   
00321   return result;
00322 }
00323 
00324 
00325 
00326 // why different ? see BoundSheetRecord
00327 EString EString::fromSheetName( const void* p, unsigned datasize )
00328 {
00329   const unsigned char* data = (const unsigned char*) p;
00330   UString str = UString::null;
00331   
00332   bool richText = false;
00333   // unsigned formatRuns = 0;
00334   
00335   unsigned len = data[0];
00336   unsigned flag = data[1];
00337   bool unicode = flag & 1;
00338   
00339   if( len > datasize-2 ) len = datasize-2;
00340   if( len == 0 ) return EString();
00341   
00342   unsigned offset = 2;
00343   
00344   if( !unicode )
00345   {
00346     char* buffer = new char[ len+1 ];
00347     memcpy( buffer, data + offset, len );
00348     buffer[ len ] = 0;
00349     str = UString( buffer );
00350     delete[] buffer;
00351   }
00352   else
00353   {
00354     for( unsigned k=0; k<len; k++ )
00355     {
00356       unsigned uchar = readU16( data + offset + k*2 );
00357       str.append( UString(UChar(uchar)) );
00358     }
00359   }
00360   
00361   EString result;
00362   result.setUnicode( unicode );
00363   result.setRichText( richText );
00364   result.setSize( datasize );
00365   result.setStr( str );
00366   
00367   return result;
00368 }
00369 
00370 //=============================================
00371 //          FormulaToken
00372 //=============================================
00373 
00374 class FormulaToken::Private
00375 {
00376 public:
00377   unsigned ver;
00378   unsigned id;
00379   std::vector<unsigned char> data;
00380 };
00381 
00382 FormulaToken::FormulaToken()
00383 {
00384   d = new Private;
00385   d->ver = Excel97;
00386   d->id = Unused;
00387 }
00388 
00389 FormulaToken::FormulaToken( unsigned t )
00390 {
00391   d = new Private;
00392   d->ver = Excel97;
00393   d->id = t;
00394 }
00395 
00396 FormulaToken::FormulaToken( const FormulaToken& token )
00397 {
00398   d = new Private;
00399   d->ver = token.d->ver;
00400   d->id = token.id();
00401   
00402   d->data.resize( token.d->data.size() );
00403   for( unsigned i = 0; i < d->data.size(); i++ )
00404     d->data[i] = token.d->data[i];
00405 }
00406 
00407 FormulaToken::~FormulaToken()
00408 {
00409   delete d;
00410 }
00411 
00412 unsigned FormulaToken::version() const
00413 {
00414   return d->ver;
00415 }
00416 
00417 void FormulaToken::setVersion( unsigned v )
00418 {
00419   d->ver = v;
00420 }
00421 
00422 unsigned FormulaToken::id() const
00423 {
00424   return d->id;
00425 }
00426 
00427 const char* FormulaToken::idAsString() const
00428 {
00429   const char* s = 0;
00430   
00431   switch( d->id )
00432   {
00433     case Matrix:       s = "Matrix"; break;
00434     case Table:        s = "Table"; break;
00435     case Add:          s = "Add"; break;
00436     case Sub:          s = "Sub"; break;
00437     case Mul:          s = "Mul"; break;
00438     case Div:          s = "Div"; break;
00439     case Power:        s = "Power"; break;
00440     case Concat:       s = "Concat"; break;
00441     case LT:           s = "LT"; break;
00442     case LE:           s = "LE"; break;
00443     case EQ:           s = "EQ"; break;
00444     case GE:           s = "GE"; break;
00445     case GT:           s = "GT"; break;
00446     case NE:           s = "NE"; break;
00447     case Intersect:    s = "Intersect"; break;
00448     case List:         s = "List"; break;
00449     case Range:        s = "Range"; break;
00450     case UPlus:        s = "UPlus"; break;
00451     case UMinus:       s = "UMinus"; break;
00452     case Percent:      s = "Percent"; break;
00453     case Paren:        s = "Paren"; break;
00454     case String:       s = "String"; break;
00455     case MissArg:      s = "MissArg"; break;
00456     case ErrorCode:    s = "ErrorCode"; break;
00457     case Bool:         s = "Bool"; break;
00458     case Integer:      s = "Integer"; break;
00459     case Array:        s = "Array"; break;
00460     case Function:     s = "Function"; break;
00461     case FunctionVar:  s = "FunctionVar"; break;
00462     case Name:         s = "Name"; break;
00463     case Ref:          s = "Ref"; break;
00464     case RefErr:       s = "RefErr"; break;
00465     case RefN:         s = "RefN"; break;
00466     case Area:         s = "Area"; break;
00467     case AreaErr:      s = "AreaErr"; break;
00468     case AreaN:        s = "AreaN"; break;
00469     case NameX:        s = "NameX"; break;
00470     case Ref3d:        s = "Ref3d"; break;
00471     case RefErr3d:     s = "RefErr3d"; break;
00472     case Float:        s = "Float"; break;
00473     case Area3d:       s = "Area3d"; break;
00474     case AreaErr3d:    s = "AreaErr3d"; break;
00475     default:           s = "Unknown"; break;
00476   };
00477   
00478   return s;
00479 }
00480 
00481 
00482 unsigned FormulaToken::size() const
00483 {
00484   unsigned s = 0; // on most cases no data
00485   
00486   switch( d->id )
00487   {
00488     case Add: 
00489     case Sub: 
00490     case Mul: 
00491     case Div:
00492     case Power:
00493     case Concat:
00494     case LT:
00495     case LE:
00496     case EQ:
00497     case GE:
00498     case GT:
00499     case NE:
00500     case Intersect:
00501     case List:
00502     case Range:
00503     case UPlus:
00504     case UMinus:
00505     case Percent:
00506     case Paren:
00507     case MissArg:
00508       s = 0; break;
00509 
00510     case Attr:
00511       s = 3; break;
00512       
00513     case ErrorCode:
00514     case Bool:
00515       s = 1; break;  
00516     
00517     case Integer:
00518       s = 2; break;
00519       
00520     case Array:
00521       s = 7; break;
00522     
00523     case Function:
00524       s = 2;
00525       break;
00526     
00527     case FunctionVar:
00528       s = 3;
00529       break;
00530     
00531     case Matrix:
00532     case Table:  
00533       s = (d->ver == Excel97) ? 4 : 3;
00534       break;
00535       
00536     case Name:
00537       s = (d->ver == Excel97) ? 4 : 14;
00538       break;
00539     
00540     case Ref:
00541     case RefErr:
00542     case RefN:
00543       s = (d->ver == Excel97) ? 4 : 3;
00544       break;
00545     
00546     case Area:
00547     case AreaErr:
00548     case AreaN:
00549       s = (d->ver == Excel97) ? 8 : 6;
00550       break;
00551     
00552     case NameX:
00553       s = (d->ver == Excel97) ? 6 : 24;
00554       break;
00555     
00556     case Ref3d:
00557     case RefErr3d:
00558       s = (d->ver == Excel97) ? 6 : 27;
00559       break;
00560       
00561     case Float:
00562       s = 8; break;  
00563       
00564     case Area3d:
00565     case AreaErr3d:
00566       s = (d->ver == Excel97) ? 10 : 20;
00567       break;  
00568       
00569     default:
00570       // WARNING this is unhandled case
00571       break;
00572   };
00573   
00574   return s;
00575 }
00576 
00577 void FormulaToken::setData( unsigned size, const unsigned char* data )
00578 {
00579   d->data.resize( size );
00580   for( unsigned i = 0; i < size; i++ )
00581     d->data[i] = data[i];
00582 }
00583 
00584 Value FormulaToken::value() const
00585 {
00586   Value result;
00587 
00588   unsigned char* buf;
00589   buf = new unsigned char[d->data.size()];
00590   for( unsigned k=0; k<d->data.size(); k++ )
00591     buf[k] = d->data[k];
00592 
00593   // FIXME sanity check: verify size of data  
00594   switch( d->id )
00595   {
00596     case ErrorCode:
00597       result = errorAsValue( buf[0] );
00598       break;
00599     
00600     case Bool:    
00601       result = Value( buf[0]!=0 );
00602       break;
00603       
00604     case Integer:
00605       result = Value( (int)readU16( buf ) );
00606       break;
00607       
00608     case Float:  
00609       result = Value( readFloat64( buf ) );
00610       break;
00611      
00612     case String:
00613       {
00614         EString estr = (version()==Excel97) ? 
00615           EString::fromUnicodeString( buf, false, d->data.size() ) :
00616           EString::fromByteString( buf, false, d->data.size() );
00617         result = Value( estr.str() );  
00618       }
00619       break;  
00620       
00621     default: break;  
00622   }
00623   
00624   delete [] buf;
00625   
00626   return result;  
00627 }
00628 
00629 unsigned FormulaToken::functionIndex() const
00630 {
00631   // FIXME check data size
00632   unsigned index = 0;
00633   unsigned char buf[2];
00634 
00635   if( d->id == Function )
00636   {
00637     buf[0] = d->data[0];
00638     buf[1] = d->data[1];
00639     index = readU16( buf );
00640   }
00641 
00642   if( d->id == FunctionVar )
00643   {
00644     buf[0] = d->data[1];
00645     buf[1] = d->data[2];
00646     index = readU16( buf );
00647   }
00648 
00649   return index;
00650 }
00651 
00652 struct FunctionEntry
00653 {
00654     const char *name;
00655     int params;
00656 };
00657 
00658 static const FunctionEntry FunctionEntries[] =
00659 {
00660   { "COUNT",           1 },     // 0
00661   { "IF",              0 },     // 1
00662   { "ISNV",            1 },     // 2
00663   { "ISERROR",         1 },     // 3
00664   { "SUM",             0 },     // 4
00665   { "AVERAGE",         0 },     // 5
00666   { "MIN",             0 },     // 6
00667   { "MAX",             0 },     // 7
00668   { "ROW",             0 },     // 8
00669   { "COLUMN",          0 },     // 9
00670   { "NOVALUE",         0 },     // 10
00671   { "NPV",             0 },     // 11
00672   { "STDEV",           0 },     // 12
00673   { "DOLLAR",          0 },     // 13
00674   { "FIXED",           0 },     // 14
00675   { "SIN",             1 },     // 15
00676   { "COS",             1 },     // 16
00677   { "TAN",             1 },     // 17
00678   { "ATAN",            1 },     // 18
00679   { "PI",              0 },     // 19
00680   { "SQRT",            1 },     // 20
00681   { "EXP",             1 },     // 21
00682   { "LN",              1 },     // 22
00683   { "LOG10",           1 },     // 23
00684   { "ABS",             1 },     // 24
00685   { "INT",             1 },     // 25
00686   { "SIGN",            1 },     // 26
00687   { "ROUND",           2 },     // 27
00688   { "LOOKUP",          0 },     // 28
00689   { "INDEX",           0 },     // 29
00690   { "REPT",            2 },     // 30
00691   { "MID",             3 },     // 31
00692   { "LEN",             1 },     // 32
00693   { "VALUE",           1 },     // 33
00694   { "TRUE",            0 },     // 34
00695   { "FALSE",           0 },     // 35
00696   { "AND",             0 },     // 36
00697   { "OR",              0 },     // 37
00698   { "NOT",             1 },     // 38
00699   { "MOD",             2 },     // 39
00700   { "DCOUNT",          3 },     // 40
00701   { "DSUM",            3 },     // 41
00702   { "DAVERAGE",        3 },     // 42
00703   { "DMIN",            3 },     // 43
00704   { "DMAX",            3 },     // 44
00705   { "DSTDEV",          3 },     // 45
00706   { "VAR",             0 },     // 46
00707   { "DVAR",            3 },     // 47
00708   { "TEXT",            2 },     // 48
00709   { "LINEST",          0 },     // 49
00710   { "TREND",           0 },     // 50
00711   { "LOGEST",           0 },     // 51
00712   { "GROWTH",          0 },     // 52
00713   { "GOTO",            0 },     // 53
00714   { "HALT",            0 },     // 54
00715   { "Unknown55",       0 },     // 55
00716   { "PV",              0 },     // 56
00717   { "FV",              0 },     // 57
00718   { "NPER",            0 },     // 58
00719   { "PMT",             0 },     // 59
00720   { "RATE",            0 },     // 60
00721   { "MIRR",            3 },     // 61
00722   { "IRR",             0 },     // 62
00723   { "RAND",            0 },     // 63
00724   { "MATCH",           0 },     // 64
00725   { "DATE",            3 },     // 65
00726   { "TIME",            3 },     // 66
00727   { "DAY",             1 },     // 67
00728   { "MONTH",           1 },     // 68
00729   { "YEAR",            1 },     // 69
00730   { "DAYOFWEEK",       0 },     // 70
00731   { "HOUR",            1 },     // 71
00732   { "MIN",             1 },     // 72
00733   { "SEC",             1 },     // 73
00734   { "NOW",             0 },     // 74
00735   { "AREAS",           1 },     // 75
00736   { "ROWS",            1 },     // 76
00737   { "COLUMNS",         1 },     // 77
00738   { "OFFSET",          0 },     // 78
00739   { "ABSREF",          2 },     // 79
00740   { "RELREF",          0 },     // 80
00741   { "ARGUMENT",        0 },     // 81
00742   { "SEARCH",          0 },     // 82
00743   { "TRANSPOSE",       1 },     // 83
00744   { "ERROR",           0 },     // 84
00745   { "STEP",            0 },     // 85
00746   { "TYPE",            1 },     // 86
00747   { "ECHO",            0 },
00748   { "SETNAME",         0 },
00749   { "CALLER",          0 },
00750   { "DEREF",           0 },
00751   { "WINDOWS",         0 },
00752   { "SERIES",          4 },
00753   { "DOCUMENTS",       0 },
00754   { "ACTIVECELL",      0 },
00755   { "SELECTION",       0 },
00756   { "RESULT",          0 },
00757   { "ATAN2",           2 },     // 97
00758   { "ASIN",            1 },     // 98
00759   { "ACOS",            1 },     // 99
00760   { "CHOOSE",          0 },     // 100
00761   { "HLOOKUP",         0 },     // 101
00762   { "VLOOKUP",         0 },     // 102
00763   { "LINKS",           0 },  
00764   { "INPUT",           0 },
00765   { "ISREF",           1 },     // 105
00766   { "GETFORMULA",      0 },
00767   { "GETNAME",         0 },
00768   { "SETVALUE",        0 },
00769   { "LOG",             0 },     // 109
00770   { "EXEC",            0 },
00771   { "CHAR",            1 },     // 111
00772   { "LOWER",           1 },     // 112
00773   { "UPPER",           1 },     // 113
00774   { "PROPER",          1 },     // 114
00775   { "LEFT",            0 },     // 115
00776   { "RIGHT",           0 },     // 116
00777   { "EXACT",           2 },     // 117
00778   { "TRIM",            1 },     // 118
00779   { "REPLACE",         4 },     // 119
00780   { "SUBSTITUTE",      0 },     // 120
00781   { "CODE",            1 },     // 121
00782   { "NAMES",           0 },
00783   { "DIRECTORY",       0 },
00784   { "FIND",            0 },     // 124
00785   { "CELL",            0 },     // 125
00786   { "ISERR",           1 },     // 126
00787   { "ISTEXT",          1 },     // 127
00788   { "ISNUMBER",        1 },     // 128
00789   { "ISBLANK",         1 },     // 129
00790   { "T",               1 },     // 130
00791   { "N",               1 },     // 131
00792   { "FOPEN",           0 },
00793   { "FCLOSE",          0 },
00794   { "FSIZE",           0 },
00795   { "FREADLN",         0 },
00796   { "FREAD",           0 },
00797   { "FWRITELN",        0 },
00798   { "FWRITE",          0 },
00799   { "FPOS",            0 },
00800   { "DATEVALUE",       1 },     // 140
00801   { "TIMEVALUE",       1 },     // 141
00802   { "SLN",             3 },     // 142
00803   { "SYD",             4 },     // 143
00804   { "DDB",             0 },     // 144
00805   { "GETDEF",          0 },
00806   { "REFTEXT",         0 },
00807   { "TEXTREF",         0 },
00808   { "INDIRECT",        0 },     // 148
00809   { "REGISTER",        0 },
00810   { "CALL",            0 },
00811   { "ADDBAR",          0 },
00812   { "ADDMENU",         0 },
00813   { "ADDCOMMAND",      0 },
00814   { "ENABLECOMMAND",   0 },
00815   { "CHECKCOMMAND",    0 },
00816   { "RENAMECOMMAND",   0 },
00817   { "SHOWBAR",         0 },
00818   { "DELETEMENU",      0 },
00819   { "DELETECOMMAND",   0 },
00820   { "GETCHARTITEM",    0 },
00821   { "DIALOGBOX",       0 },
00822   { "CLEAN",           1 },     // 162
00823   { "MDETERM",         1 },     // 163
00824   { "MINVERSE",        1 },     // 164
00825   { "MMULT",           2 },     // 165
00826   { "FILES",           0 },  
00827   { "IPMT",            0 },     // 167
00828   { "PPMT",            0 },     // 168
00829   { "COUNTA",          0 },     // 169
00830   { "CANCELKEY",       1 }, 
00831   { "Unknown171",      0 },
00832   { "Unknown172",      0 },
00833   { "Unknown173",      0 },
00834   { "Unknown174",      0 },
00835   { "INITIATE",        0 },
00836   { "REQUEST",         0 },
00837   { "POKE",            0 },
00838   { "EXECUTE",         0 },
00839   { "TERMINATE",       0 },
00840   { "RESTART",         0 },
00841   { "HELP",            0 },
00842   { "GETBAR",          0 },  
00843   { "PRODUCT",         0 },     // 183
00844   { "FACT",            1 },     // 184
00845   { "GETCELL",         0 },  
00846   { "GETWORKSPACE",    0 },
00847   { "GETWINDOW",       0 },
00848   { "GETDOCUMENT",     0 },
00849   { "DPRODUCT",        3 },     // 189
00850   { "ISNONTEXT",       1 },     // 190
00851   { "GETNOTE",         0 },
00852   { "NOTE",            0 },
00853   { "STDEVP",          0 },     // 193
00854   { "VARP",            0 },     // 194
00855   { "DSTDEVP",         3 },     // 195
00856   { "DVARP",           3 },     // 196
00857   { "TRUNC",           0 },     // 197
00858   { "ISLOGICAL",       1 },     // 198
00859   { "DCOUNTA",         3 },     // 199
00860   { "DELETEBAR",       0 },
00861   { "UNREGISTER",      0 },
00862   { "Unknown202",      0 },
00863   { "Unknown203",      0 },
00864   { "USDOLLAR",        0 },
00865   { "FINDB",           0 },
00866   { "SEARCHB",         0 },
00867   { "REPLACEB",        0 },
00868   { "LEFTB",           0 },
00869   { "RIGHTB",          0 },
00870   { "MIDB",            0 },
00871   { "LENB",            0 },  
00872   { "ROUNDUP",         2 },     // 212
00873   { "ROUNDDOWN",       2 },     // 213
00874   { "ASC",             0 },
00875   { "DBCS",            0 },
00876   { "RANK",            0 },     // 216
00877   { "Unknown217",      0 },
00878   { "Unknown218",      0 },  
00879   { "ADDRESS",         0 },     // 219
00880   { "GETDIFFDATE360",  0 },     // 220
00881   { "CURRENTDATE",     0 },     // 221
00882   { "VBD",             0 },     // 222
00883   { "Unknown223",      0 },
00884   { "Unknown224",      0 }, 
00885   { "Unknown225",      0 },
00886   { "Unknown226",      0 },
00887   { "MEDIAN",          0 },     // 227
00888   { "SUMPRODUCT",      0 },     // 228
00889   { "SINH",            1 },     // 229
00890   { "COSH",            1 },     // 230
00891   { "TANH",            1 },     // 231
00892   { "ASINH",           1 },     // 232
00893   { "ACOSH",           1 },     // 233
00894   { "ATANH",           1 },     // 234
00895   { "DGET",            3 },     // 235
00896   { "CREATEOBJECT",    0 },
00897   { "VOLATILE",        0 },
00898   { "LASTERROR",       0 },
00899   { "CUSTOMUNDO",      0 },
00900   { "CUSTOMREPEAT",    0 },
00901   { "FORMULACONVERT",  0 },
00902   { "GETLINKINFO",     0 },
00903   { "TEXTBOX",         0 },  
00904   { "INFO",            1 },     // 244
00905   { "GROUP",           0 },
00906   { "GETOBJECT",       0 },  
00907   { "DB",              0 },     // 247
00908   { "PAUSE",           0 },
00909   { "Unknown249",      0 },
00910   { "Unknown250",      0 },
00911   { "RESUME",          0 },
00912   { "FREQUENCY",       2 },     // 252
00913   { "ADDTOOLBAR",      0 },
00914   { "DELETETOOLBAR",   0 },
00915   { "Unknown255",      0 }, 
00916   { "RESETTOOLBAR",    0 },
00917   { "EVALUATE",        0 },
00918   { "GETTOOLBAR",      0 },
00919   { "GETTOOL",         0 },
00920   { "SPELLINGCHECK",   0 },  
00921   { "ERRORTYPE",       1 },     // 261
00922   { "APPTITLE",        0 },
00923   { "WINDOWTITLE",     0 },
00924   { "SAVETOOLBAR",     0 },
00925   { "ENABLETOOL",      0 },
00926   { "PRESSTOOL",       0 },
00927   { "REGISTERID",      0 },
00928   { "GETWORKBOOK",     0 },
00929   { "AVEDEV",          0 },     // 269
00930   { "BETADIST",        0 },     // 270
00931   { "GAMMALN",         1 },     // 271
00932   { "BETAINV",         0 },     // 272
00933   { "BINOMDIST",       4 },     // 273
00934   { "CHIDIST",         2 },     // 274
00935   { "CHIINV",          2 },     // 275
00936   { "COMBIN",          2 },     // 276
00937   { "CONFIDENCE",      3 },     // 277
00938   { "CRITBINOM",       3 },     // 278
00939   { "EVEN",            1 },     // 279
00940   { "EXPONDIST",       3 },     // 280
00941   { "FDIST",           3 },     // 281
00942   { "FINV",            3 },     // 282
00943   { "FISHER",          1 },     // 283
00944   { "FISHERINV",       1 },     // 284
00945   { "FLOOR",           2 },     // 285
00946   { "GAMMADIST",       4 },     // 286
00947   { "GAMMAINV",        3 },     // 287
00948   { "CEIL",            2 },     // 288
00949   { "HYPGEOMDIST",     4 },     // 289
00950   { "LOGNORMDIST",     3 },     // 290
00951   { "LOGINV",          3 },     // 291
00952   { "NEGBINOMDIST",    3 },     // 292
00953   { "NORMDIST",        4 },     // 293
00954   { "NORMSDIST",       1 },     // 294
00955   { "NORMINV",         3 },     // 295
00956   { "NORMSINV",        1 },     // 296
00957   { "STANDARDIZE",     3 },     // 297
00958   { "ODD",             1 },     // 298
00959   { "PERMUT",          2 },     // 299
00960   { "POISSON",         3 },     // 300
00961   { "TDIST",           3 },     // 301
00962   { "WEIBULL",         4 },     // 302
00963   { "SUMXMY2",         2 },     // 303
00964   { "SUMX2MY2",        2 },     // 304
00965   { "SUMX2DY2",        2 },     // 305
00966   { "CHITEST",         2 },     // 306
00967   { "CORREL",          2 },     // 307
00968   { "COVAR",           2 },     // 308
00969   { "FORECAST",        3 },     // 309
00970   { "FTEST",           2 },     // 310
00971   { "INTERCEPT",       2 },     // 311
00972   { "PEARSON",         2 },     // 312
00973   { "RSQ",             2 },     // 313
00974   { "STEYX",           2 },     // 314
00975   { "SLOPE",           2 },     // 315
00976   { "TTEST",           4 },     // 316
00977   { "PROB",            0 },     // 317
00978   { "DEVSQ",           0 },     // 318
00979   { "GEOMEAN",         0 },     // 319
00980   { "HARMEAN",         0 },     // 320
00981   { "SUMSQ",           0 },     // 321
00982   { "KURT",            0 },     // 322
00983   { "SKEW",            0 },     // 323
00984   { "ZTEST",           0 },     // 324
00985   { "LARGE",           2 },     // 325
00986   { "SMALL",           2 },     // 326
00987   { "QUARTILE",        2 },     // 327
00988   { "PERCENTILE",      2 },     // 328
00989   { "PERCENTRANK",     0 },     // 329
00990   { "MODALVALUE",      0 },     // 330
00991   { "TRIMMEAN",        2 },     // 331
00992   { "TINV",            2 },     // 332
00993   { "Unknown333",      0 },
00994   { "MOVIECOMMAND",    0 },
00995   { "GETMOVIE",        0 },  
00996   { "CONCATENATE",     0 },     // 336
00997   { "POWER",           2 },     // 337
00998   { "PIVOTADDDATA",    0 },
00999   { "GETPIVOTTABLE",   0 },
01000   { "GETPIVOTFIELD",   0 },
01001   { "GETPIVOTITEM",    0 },  
01002   { "RADIANS",         1 },     // 342
01003   { "DEGREES",         1 },     // 343
01004   { "SUBTOTAL",        0 },     // 344
01005   { "SUMIF",           0 },     // 345
01006   { "COUNTIF",         2 },     // 346
01007   { "COUNTBLANK",      1 },     // 347
01008   { "SCENARIOGET",     0 },
01009   { "OPTIONSLISTSGET", 0 },
01010   { "ISPMT",           4 },
01011   { "DATEDIF",         3 },
01012   { "DATESTRING",      0 },
01013   { "NUMBERSTRING",    0 },
01014   { "ROMAN",           0 },     // 354
01015   { "OPENDIALOG",      0 },
01016   { "SAVEDIALOG",      0 },
01017   { "VIEWGET",         0 },
01018   { "GETPIVOTDATA",    2 },     // 358
01019   { "HYPERLINK",       1 },
01020   { "PHONETIC",        0 },
01021   { "AVERAGEA",        0 },     // 361
01022   { "MAXA",            0 },     // 362
01023   { "MINA",            0 },     // 363
01024   { "STDEVPA",         0 },     // 364
01025   { "VARPA",           0 },     // 365
01026   { "STDEVA",          0 },     // 366
01027   { "VARA",            0 },     // 367
01028 };
01029 
01030 const char* FormulaToken::functionName() const
01031 {
01032   if( functionIndex() > 367 ) return 0;
01033   return FunctionEntries[ functionIndex() ].name;
01034 }
01035 
01036 unsigned FormulaToken::functionParams() const
01037 {
01038   unsigned params = 0;
01039 
01040   if( d->id == Function )
01041   {
01042     if( functionIndex() > 367 ) return 0;
01043     params = FunctionEntries[ functionIndex() ].params;
01044   }
01045 
01046   if( d->id == FunctionVar )
01047   {
01048     params = (unsigned)d->data[0];
01049     params &= 0x7f;
01050   }
01051 
01052   return params;
01053 }
01054 
01055 unsigned FormulaToken::attr() const
01056 {
01057   unsigned attr = 0;
01058   if( d->id == Attr )
01059   {
01060     attr = (unsigned) d->data[0];
01061   }
01062   return attr;
01063 }
01064 
01065 unsigned FormulaToken::nameIndex() const
01066 {
01067   // FIXME check data size !
01068   unsigned ni = 0;
01069   unsigned char buf[2];
01070 
01071   if( d->id == NameX )
01072   if( d->ver == Excel97 )
01073   {
01074     buf[0] = d->data[2];
01075     buf[1] = d->data[3];
01076     ni = readU16( buf );
01077   }
01078 
01079   if( d->id == NameX )
01080   if( d->ver == Excel95 )
01081   {
01082     buf[0] = d->data[10];
01083     buf[1] = d->data[11];
01084     ni = readU16( buf );
01085   }
01086 
01087   return ni;
01088 }
01089 
01090 
01091 UString FormulaToken::area( unsigned row, unsigned col ) const
01092 {
01093   // FIXME check data size !
01094   unsigned char buf[2];
01095   int row1Ref, row2Ref, col1Ref, col2Ref;
01096   bool row1Relative, col1Relative;
01097   bool row2Relative, col2Relative;
01098 
01099   if( version() == Excel97 )
01100   {
01101     buf[0] = d->data[0];
01102     buf[1] = d->data[1];
01103     row1Ref = readU16( buf );
01104 
01105     buf[0] = d->data[2];
01106     buf[1] = d->data[3];
01107     row2Ref = readU16( buf );
01108 
01109     buf[0] = d->data[4];
01110     buf[1] = d->data[5];
01111     col1Ref = readU16( buf );
01112 
01113     buf[0] = d->data[6];
01114     buf[1] = d->data[7];
01115     col2Ref = readU16( buf );
01116 
01117     row1Relative = col1Ref & 0x8000;
01118     col1Relative = col1Ref & 0x4000;
01119     col1Ref &= 0x3fff;
01120 
01121     row2Relative = col2Ref & 0x8000;
01122     col2Relative = col2Ref & 0x4000;
01123     col2Ref &= 0x3fff;
01124   }
01125   else
01126   {
01127     buf[0] = d->data[0];
01128     buf[1] = d->data[1];
01129     row1Ref = readU16( buf );
01130 
01131     buf[0] = d->data[2];
01132     buf[1] = d->data[3];
01133     row2Ref = readU16( buf );
01134 
01135     buf[0] = d->data[4];
01136     buf[1] = 0;
01137     col1Ref = readU16( buf );
01138 
01139     buf[0] = d->data[5];
01140     buf[1] = 0;
01141     col2Ref = readU16( buf );
01142 
01143     row1Relative = row2Ref & 0x8000;
01144     col1Relative = row2Ref & 0x4000;
01145     row1Ref &= 0x3fff;
01146 
01147     row2Relative = row2Ref & 0x8000;
01148     col2Relative = row2Ref & 0x4000;
01149     row2Ref &= 0x3fff;
01150   }
01151 
01152   UString result;
01153   result.append( UString("[") );  // OpenDocument format
01154   
01155   if( !col1Relative )
01156     result.append( UString("$") );
01157   result.append( Cell::columnLabel( col1Ref ) );  
01158   if( !row1Relative )
01159     result.append( UString("$") );
01160   result.append( UString::from( row1Ref+1 ) );  
01161   result.append( UString(":") );
01162   if( !col2Relative )
01163     result.append( UString("$") );
01164   result.append( Cell::columnLabel( col2Ref ) );  
01165   if( !row2Relative )
01166     result.append( UString("$") );
01167   result.append( UString::from( row2Ref+1 ) );  
01168   
01169   result.append( UString("]") );// OpenDocument format
01170 
01171   return result;  
01172 }
01173 
01174 UString FormulaToken::ref( unsigned row, unsigned col ) const
01175 {
01176   // FIXME check data size !
01177   // FIXME handle shared formula
01178   unsigned char buf[2];
01179   int rowRef, colRef;
01180   bool rowRelative, colRelative;
01181 
01182   if( version() == Excel97 )
01183   {
01184     buf[0] = d->data[0];
01185     buf[1] = d->data[1];
01186     rowRef = readU16( buf );
01187 
01188     buf[0] = d->data[2];
01189     buf[1] = d->data[3];
01190     colRef = readU16( buf );
01191 
01192     rowRelative = colRef & 0x8000;
01193     colRelative = colRef & 0x4000;
01194     colRef &= 0x3fff;
01195   }
01196   else
01197   {
01198     buf[0] = d->data[0];
01199     buf[1] = d->data[1];
01200     rowRef = readU16( buf );
01201 
01202     buf[0] = d->data[2];
01203     buf[1] = 0;
01204     colRef = readU16( buf );
01205 
01206     rowRelative = rowRef & 0x8000;
01207     colRelative = rowRef & 0x4000;
01208     rowRef &= 0x3fff;
01209   }
01210 
01211   UString result;
01212 
01213   result.append( UString("[") );  // OpenDocument format
01214   
01215   if( !colRelative )
01216     result.append( UString("$") );
01217   result.append( Cell::columnLabel( colRef ) );  
01218   if( !rowRelative )
01219     result.append( UString("$") );
01220   result.append( UString::from( rowRef+1 ) );  
01221   
01222   result.append( UString("]") );// OpenDocument format
01223 
01224   return result;  
01225 }
01226 
01227 std::ostream& Swinder::operator<<( std::ostream& s,  Swinder::FormulaToken token )
01228 {
01229   s << std::setw(2) << std::hex << token.id() << std::dec;
01230   // s  << "  Size: " << std::dec << token.size();
01231   s << "  ";
01232   
01233   switch( token.id() )
01234   {
01235     case FormulaToken::ErrorCode:
01236     case FormulaToken::Bool:
01237     case FormulaToken::Integer:
01238     case FormulaToken::Float:
01239     case FormulaToken::String:
01240       {
01241         Value v = token.value();
01242         s << v;
01243       }
01244       break;
01245       
01246     case FormulaToken::Function:
01247       s << "Function " << token.functionName();  
01248       break;
01249       
01250     default:  
01251       s << token.idAsString();
01252       break;
01253   }
01254   
01255   return s;
01256 }
01257 
01258 //=============================================
01259 //          CellInfo
01260 //=============================================
01261 
01262 class CellInfo::Private
01263 {
01264 public:
01265   unsigned row;
01266   unsigned column;
01267   unsigned xfIndex;
01268 };
01269 
01270 CellInfo::CellInfo()
01271 {
01272   info = new CellInfo::Private();
01273   info->row = 0;
01274   info->column = 0;
01275   info->xfIndex = 0;
01276 }
01277 
01278 CellInfo::~CellInfo()
01279 {
01280   delete info;
01281 }
01282 
01283 unsigned CellInfo::row() const
01284 {
01285   return info->row;
01286 }
01287 
01288 void CellInfo::setRow( unsigned r )
01289 {
01290   info->row = r;
01291 }
01292 
01293 unsigned CellInfo::column() const
01294 {
01295   return info->column;
01296 }
01297 
01298 void CellInfo::setColumn( unsigned c )
01299 {
01300   info->column = c;
01301 }
01302 
01303 unsigned CellInfo::xfIndex() const
01304 {
01305   return info->xfIndex;
01306 }
01307 
01308 void CellInfo::setXfIndex( unsigned i )
01309 {
01310   info->xfIndex = i;
01311 }
01312 
01313 //=============================================
01314 //          ColumnSpanInfo
01315 //=============================================
01316 
01317 class ColumnSpanInfo::Private
01318 {
01319 public:
01320   unsigned firstColumn;
01321   unsigned lastColumn;
01322 };
01323 
01324 ColumnSpanInfo::ColumnSpanInfo()
01325 {
01326   spaninfo = new ColumnSpanInfo::Private();
01327   spaninfo->firstColumn = 0;
01328   spaninfo->lastColumn = 0;
01329 }
01330 
01331 ColumnSpanInfo::~ColumnSpanInfo()
01332 {
01333   delete spaninfo;
01334 }
01335 
01336 unsigned ColumnSpanInfo::firstColumn() const
01337 {
01338   return spaninfo->firstColumn;
01339 }
01340 
01341 void ColumnSpanInfo::setFirstColumn( unsigned c )
01342 {
01343   spaninfo->firstColumn = c;
01344 }
01345 
01346 unsigned ColumnSpanInfo::lastColumn() const
01347 {
01348   return spaninfo->lastColumn;
01349 }
01350 
01351 void ColumnSpanInfo::setLastColumn( unsigned c )
01352 {
01353   spaninfo->lastColumn = c;
01354 }
01355 
01356 // ========== base record ==========
01357 
01358 const unsigned int Record::id = 0; // invalid of-course
01359 
01360 Record::Record()
01361 {
01362   stream_position = 0;
01363   ver = Excel97;
01364 }
01365 
01366 Record::~Record()
01367 {
01368 }
01369 
01370 Record* Record::create( unsigned type )
01371 {
01372   Record* record = 0;
01373   
01374   if( type == BOFRecord::id )
01375     record = new BOFRecord();
01376     
01377   else if( type == EOFRecord::id )
01378     record = new EOFRecord();
01379     
01380   if( type == BackupRecord::id )
01381     record = new BackupRecord();
01382     
01383   if( type == BlankRecord::id )
01384     record = new BlankRecord();
01385     
01386   if( type == BoolErrRecord::id )
01387     record = new BoolErrRecord();
01388     
01389   if( type == BottomMarginRecord::id )
01390     record = new BottomMarginRecord();
01391     
01392   if( type == BoundSheetRecord::id )
01393     record = new BoundSheetRecord();
01394     
01395   if( type == CalcModeRecord::id )
01396     record = new CalcModeRecord();
01397     
01398   if( type == ColInfoRecord::id )
01399     record = new ColInfoRecord();
01400     
01401   if( type == DateModeRecord::id )
01402     record = new DateModeRecord();
01403     
01404   if( type == DimensionRecord::id )
01405     record = new DimensionRecord();
01406     
01407   if( type == ExternNameRecord::id )
01408     record = new ExternNameRecord();
01409     
01410   else if( type == FilepassRecord::id )
01411     record = new FilepassRecord();
01412     
01413   else if( type == FontRecord::id )
01414     record = new FontRecord();
01415     
01416   else if( type == FooterRecord::id )
01417     record = new FooterRecord();
01418     
01419   else if( type == FormatRecord::id )
01420     record = new FormatRecord();
01421     
01422   else if( type == FormulaRecord::id )
01423     record = new FormulaRecord();
01424     
01425   else if( type == HeaderRecord::id )
01426     record = new HeaderRecord();
01427     
01428   else if( type == LabelRecord::id )
01429     record = new LabelRecord();
01430     
01431   else if( type == LabelSSTRecord::id )
01432     record = new LabelSSTRecord();
01433     
01434   if( type == LeftMarginRecord::id )
01435     record = new LeftMarginRecord();
01436     
01437   else if( type == MergedCellsRecord::id )
01438     record = new MergedCellsRecord();
01439     
01440   else if( type == MulBlankRecord::id )
01441     record = new MulBlankRecord();
01442     
01443   else if( type == MulRKRecord::id )
01444     record = new MulRKRecord();
01445     
01446   if( type == NameRecord::id )
01447     record = new NameRecord();
01448     
01449   else if( type == NumberRecord::id )
01450     record = new NumberRecord();
01451     
01452   else if( type == PaletteRecord::id )
01453     record = new PaletteRecord();
01454     
01455   if( type == RightMarginRecord::id )
01456     record = new RightMarginRecord();
01457     
01458   else if( type == RKRecord::id )
01459     record = new RKRecord();
01460     
01461   else if( type == RowRecord::id )
01462     record = new RowRecord();
01463     
01464   else if( type == RStringRecord::id )
01465     record = new RStringRecord();
01466     
01467   else if( type == SSTRecord::id )
01468     record = new SSTRecord();
01469   
01470   else if( type == StringRecord::id )
01471     record = new StringRecord();
01472   
01473   else if( type == XFRecord::id )
01474     record = new XFRecord();
01475   
01476   else if( type == TopMarginRecord::id )
01477     record = new TopMarginRecord();
01478     
01479   return record;
01480 }
01481 
01482 void Record::setPosition( unsigned pos )
01483 {
01484   stream_position = pos;
01485 }
01486   
01487 unsigned Record::position() const
01488 {
01489   return stream_position;
01490 }
01491 
01492 void Record::setData( unsigned, const unsigned char* )
01493 {
01494 }
01495 
01496 void Record::dump( std::ostream& ) const
01497 {
01498   // nothing to dump
01499 }
01500 
01501 // ========== BACKUP ========== 
01502 
01503 const unsigned int BackupRecord::id = 0x0040;
01504 
01505 class BackupRecord::Private
01506 {
01507 public:
01508   bool backup;
01509 };
01510 
01511 BackupRecord::BackupRecord():
01512   Record()
01513 {
01514   d = new BackupRecord::Private();
01515   d->backup = false;
01516 }
01517 
01518 BackupRecord::~BackupRecord()
01519 {
01520   delete d;
01521 }
01522 
01523 bool BackupRecord::backup() const
01524 {
01525   return d->backup;
01526 }
01527 
01528 void BackupRecord::setBackup( bool b )
01529 {
01530   d->backup = b;
01531 }
01532 
01533 void BackupRecord::setData( unsigned size, const unsigned char* data )
01534 {
01535   if( size < 2 ) return;
01536   
01537   unsigned flag = readU16( data );
01538   d->backup = flag != 0;
01539 }
01540 
01541 void BackupRecord::dump( std::ostream& out ) const
01542 {
01543   out << "BACKUP" << std::endl;
01544   out << "     Backup on save : " << (backup() ? "Yes" : "No") << std::endl;
01545 }
01546 
01547 // ========== BLANK ========== 
01548 
01549 const unsigned int BlankRecord::id = 0x0201;
01550 
01551 BlankRecord::BlankRecord():
01552   Record(), CellInfo()
01553 {
01554 }
01555 
01556 void BlankRecord::setData( unsigned size, const unsigned char* data )
01557 {
01558   if( size < 6 ) return;
01559 
01560   setRow( readU16( data ) );
01561   setColumn( readU16( data+2 ) );
01562   setXfIndex( readU16( data+4 ) );
01563 }
01564 
01565 void BlankRecord::dump( std::ostream& out ) const
01566 {
01567   out << "BLANK" << std::endl;
01568   out << "                Row : " << row() << std::endl;
01569   out << "             Column : " << column() << std::endl;
01570   out << "           XF Index : " << xfIndex() << std::endl;
01571 }
01572 
01573 
01574 // ========== BOF ========== 
01575 
01576 const unsigned int BOFRecord::id = 0x0809;
01577 
01578 // helper class for BOFRecord
01579 class BOFRecord::Private
01580 {
01581 public:
01582   unsigned version;  // 0x0500=Excel95, 0x0600=Excel97, and so on
01583   unsigned type;
01584   unsigned build;
01585   unsigned year;
01586   unsigned history;
01587   unsigned rversion;
01588 };
01589 
01590 // constructor of BOFRecord
01591 BOFRecord::BOFRecord():
01592   Record()
01593 {
01594   d = new BOFRecord::Private();
01595   d->version  = 0x600; // BIFF8;
01596   d->type     = 0;
01597   d->build    = 0;
01598   d->year     = 0;
01599   d->history  = 0;
01600   d->rversion = 0;
01601 }
01602 
01603 // destructor of BOFRecord
01604 BOFRecord::~BOFRecord()
01605 {
01606   delete d;
01607 }
01608 
01609 void BOFRecord::setData( unsigned size, const unsigned char* data )
01610 {
01611   if( size < 4 ) return;
01612   
01613   d->version  = readU16( data );
01614   d->type     = readU16( data+2 );
01615   if( size > 6 )
01616   {
01617     d->build    = readU16( data+4 );
01618     d->year     = readU16( data+6);
01619     if( size > 12 )
01620     {
01621       d->history  = readU32( data+8 );
01622       d->rversion = readU32( data+12 );
01623     }
01624   }
01625 }
01626 
01627 unsigned BOFRecord::version() const
01628 {
01629   unsigned ver = UnknownExcel;
01630   switch( d->version )
01631   {
01632     case 0x0500 : ver = Excel95; break;
01633     case 0x0600 : ver = Excel97; break;
01634     default: break;
01635   }
01636   return ver;
01637 }
01638 
01639 const char* BOFRecord::versionAsString() const
01640 {
01641   const char *result = "Unknown";
01642   switch( version() )
01643   {
01644     case Excel95 : result = "Excel95"; break;
01645     case Excel97 : result = "Excel97"; break;
01646     default: break;
01647   }
01648   return result;
01649 }
01650 
01651 unsigned BOFRecord::type() const
01652 {
01653   unsigned result = UnknownType;
01654   switch( d->type )
01655   {
01656     case 0x005  : result = Workbook; break;
01657     case 0x006  : result = VBModule; break;
01658     case 0x010  : result = Worksheet; break;
01659     case 0x020  : result = Chart; break;
01660     case 0x040  : result = MacroSheet; break;
01661     case 0x100  : result = Workspace; break;
01662     default: break;
01663   }
01664   return result;
01665 }
01666 
01667 const char* BOFRecord::typeAsString() const
01668 {
01669   const char *result = "Unknown";
01670   switch( type() )
01671   {
01672     case Workbook   : result = "Workbook"; break;
01673     case VBModule   : result = "Visual Basic Module"; break;
01674     case Worksheet  : result = "Worksheet"; break;
01675     case Chart      : result = "Chart"; break;
01676     case MacroSheet : result = "Macro Sheet"; break;
01677     case Workspace  : result = "Workspace File"; break;
01678     default: break;
01679   }
01680   return result;
01681 }
01682 
01683 void BOFRecord::dump( std::ostream& out ) const
01684 {
01685   out << "BOF" << std::endl;
01686   out << "            Version : 0x" << std::hex << d->version << " (" << versionAsString() << ")" << std::endl;
01687   out << "               Type : 0x" << d->type << " (" << typeAsString() << ")" << std::endl;
01688   out << "              Build : 0x" << d->build << std::endl;
01689   out << "               Year : " << std::dec << d->year << std::endl;
01690   out << "            History : 0x" << std::hex << d->history << std::endl;
01691   out << "           RVersion : 0x" << d->rversion << std::endl;
01692   out << std::dec;
01693 }
01694 
01695 // ========== BOOLERR ==========
01696 
01697 const unsigned int BoolErrRecord::id = 0x0205;
01698 
01699 class BoolErrRecord::Private
01700 {
01701 public:
01702   Value value;
01703 };
01704 
01705 BoolErrRecord::BoolErrRecord():
01706   Record(), CellInfo()
01707 {
01708   d = new BoolErrRecord::Private();
01709   d->value = Value( false );
01710 }
01711 
01712 BoolErrRecord::~BoolErrRecord()
01713 {
01714   delete d;
01715 }
01716 
01717 void BoolErrRecord::setData( unsigned size, const unsigned char* data )
01718 {
01719   if( size != 8 ) return;
01720 
01721   setRow( readU16( data ) );
01722   setColumn( readU16( data+2 ) );
01723   setXfIndex( readU16( data+4 ) );
01724 
01725   switch( data[7] )
01726   {
01727   case 0 :
01728     d->value = Value( data[6] ? true : false );
01729     break;
01730   case 1 :
01731     d->value = errorAsValue( data[6] );
01732     break;
01733   default:
01734     // bad bad bad
01735     std::cerr << "Warning: bad BOOLERR record" << std::endl;
01736     break;
01737   }
01738 }
01739 
01740 Value BoolErrRecord::value() const
01741 {
01742   return d->value;
01743 }
01744 
01745 void BoolErrRecord::dump( std::ostream& out ) const
01746 {
01747   out << "BOOLERR" << std::endl;
01748   out << "             Column : " << column() << std::endl;
01749   out << "                Row : " << row() << std::endl;
01750   out << "            XFIndex : " << xfIndex() << std::endl;
01751   out << "              Value : " << value() << std::endl;
01752 }
01753 
01754 // ========== BOTTOMMARGIN ==========
01755 
01756 const unsigned int BottomMarginRecord::id = 0x0029;
01757 
01758 class BottomMarginRecord::Private
01759 {
01760 public:
01761   double bottomMargin;
01762 };
01763 
01764 BottomMarginRecord::BottomMarginRecord():
01765   Record()
01766 {
01767   d = new BottomMarginRecord::Private();
01768   d->bottomMargin = 1.0;
01769 }
01770 
01771 BottomMarginRecord::~BottomMarginRecord()
01772 {
01773   delete d;
01774 }
01775 
01776 double BottomMarginRecord::bottomMargin() const
01777 {
01778   return d->bottomMargin;
01779 }
01780 
01781 void BottomMarginRecord::setBottomMargin( double m )
01782 {
01783   d->bottomMargin = m;
01784 }
01785 
01786 void BottomMarginRecord::setData( unsigned size, const unsigned char* data )
01787 {
01788   if( size < 8 ) return;
01789   setBottomMargin( readFloat64( data ) );
01790 }
01791 
01792 void BottomMarginRecord::dump( std::ostream& out ) const
01793 {
01794   out << "BOTTOMMARGIN" << std::endl;
01795   out << "      Bottom Margin : " << bottomMargin() << " inches" << std::endl;
01796 }
01797 
01798 
01799 // ========== BOUNDSHEET ==========
01800 
01801 const unsigned int BoundSheetRecord::id = 0x0085;
01802 
01803 // helper class for BoundSheetRecord
01804 class BoundSheetRecord::Private
01805 {
01806 public:
01807   unsigned type;  // 0=Worksheet, 2=Chart, 6=VB Module
01808   unsigned visibility; // 0=visible, 1=hidden, 2=strong hidden
01809   UString name;
01810   unsigned bofPosition;
01811 };
01812 
01813 BoundSheetRecord::BoundSheetRecord():
01814   Record()
01815 {
01816   d = new BoundSheetRecord::Private();
01817   d->type = 0;
01818   d->visibility = 0;
01819   d->name = "Sheet";
01820 }
01821 
01822 void BoundSheetRecord::setType( unsigned t )
01823 {
01824   switch( t )
01825   {
01826     case Worksheet: d->type = 0; break;
01827     case Chart:     d->type = 2; break;
01828     case VBModule:  d->type = 6; break;
01829     default: d->type = 0; break; // fallback
01830   };
01831 }
01832 
01833 unsigned BoundSheetRecord::type() const
01834 {
01835   unsigned t = Worksheet;
01836   switch( d->type )
01837   {
01838     case 0: t = Worksheet; break;
01839     case 2: t = Chart; break;
01840     case 6: t = VBModule; break;
01841     default: break;
01842   };
01843   return t;
01844 }
01845 
01846 const char* BoundSheetRecord::typeAsString() const
01847 {
01848   const char *result = "Unknown";
01849   switch( type() )
01850   {
01851     case Worksheet: result = "Worksheet"; break;
01852     case Chart:     result = "Chart"; break;
01853     case VBModule:  result = "Visual Basic Module"; break;
01854     default: break;
01855   }
01856   return result;
01857 }
01858 
01859 void BoundSheetRecord::setVisible( bool v )
01860 {
01861   d->visibility = v ? 0 : 1;
01862 }
01863 
01864 bool BoundSheetRecord::visible() const
01865 {
01866   return d->visibility == 0;
01867 }
01868 
01869 void BoundSheetRecord::setSheetName( const UString& n )
01870 {
01871   d->name = n;
01872 }
01873 
01874 UString BoundSheetRecord::sheetName() const
01875 {
01876   return d->name;
01877 }
01878 
01879 void BoundSheetRecord::setBofPosition( unsigned pos )
01880 {
01881   d->bofPosition = pos;
01882 }
01883 
01884 unsigned BoundSheetRecord::bofPosition() const
01885 {
01886   return d->bofPosition;
01887 }
01888 
01889 BoundSheetRecord::~BoundSheetRecord()
01890 {
01891   delete d;
01892 }
01893 
01894 void BoundSheetRecord::setData( unsigned size, const unsigned char* data )
01895 {
01896   if( size < 6 ) return;
01897   
01898   d->bofPosition = readU32( data );
01899   d->visibility = data[4];
01900   d->type = data[5];
01901   
01902   /* FIXME: it turned out that sheet name is not normal unicode string
01903      where the first two bytes specifies string length, but instead
01904      only the first specifies it.
01905      the next byte could be correctly interpreted as flag.
01906    */  
01907    
01908   UString name = ( version() >= Excel97 ) ?
01909     EString::fromSheetName( data+6, size-6 ).str() :
01910     EString::fromByteString( data+6, false, size-6 ).str();
01911   setSheetName( name );
01912 }
01913 
01914 void BoundSheetRecord::dump( std::ostream& out ) const
01915 {
01916   out << "BOUNDSHEET" << std::endl;
01917   out << "               Name : " << d->name << std::endl;
01918   out << "               Type : " << d->type << " (" << typeAsString() << ")" << std::endl;
01919   out << "         Visibility : " << d->visibility << " (";
01920   if( visible() ) out << "Visible"; else out << "Hidden"; out << ")" << std::endl;
01921   out << "            BOF pos : " << d->bofPosition << std::endl;
01922 }
01923 
01924 // ========== CALCMODE ========== 
01925 
01926 const unsigned int CalcModeRecord::id = 0x000d;
01927 
01928 class CalcModeRecord::Private
01929 {
01930 public:
01931   bool autoCalc;
01932 };
01933 
01934 CalcModeRecord::CalcModeRecord():
01935   Record()
01936 {
01937   d = new CalcModeRecord::Private();
01938   d->autoCalc = false;
01939 }
01940 
01941 CalcModeRecord::~CalcModeRecord()
01942 {
01943   delete d;
01944 }
01945 
01946 bool CalcModeRecord::autoCalc() const
01947 {
01948   return d->autoCalc;
01949 }
01950 
01951 void CalcModeRecord::setAutoCalc( bool b )
01952 {
01953   d->autoCalc = b;
01954 }
01955 
01956 void CalcModeRecord::setData( unsigned size, const unsigned char* data )
01957 {
01958   if( size < 2 ) return;
01959   
01960   unsigned flag = readU16( data );
01961   d->autoCalc = flag != 0;
01962 }
01963 
01964 void CalcModeRecord::dump( std::ostream& out ) const
01965 {
01966   out << "CALCMODE" << std::endl;
01967   out << "          Auto Calc : " << (autoCalc() ? "Yes" : "No") << std::endl;
01968 }
01969 
01970 // ========== COLINFO ==========
01971 
01972 const unsigned int ColInfoRecord::id = 0x007d;
01973 
01974 class ColInfoRecord::Private
01975 {
01976 public:
01977   unsigned width;
01978   unsigned xfIndex;
01979   bool hidden;
01980   bool collapsed;
01981   unsigned outlineLevel;
01982 };
01983 
01984 ColInfoRecord::ColInfoRecord():
01985   Record(), ColumnSpanInfo()
01986 {
01987   d = new ColInfoRecord::Private();
01988   d->width        = 2340;
01989   d->xfIndex      = 0;
01990   d->hidden       = false;
01991   d->collapsed    = false;
01992   d->outlineLevel = 0;
01993 }
01994 
01995 ColInfoRecord::~ColInfoRecord()
01996 {
01997   delete d;
01998 }
01999 
02000 // FIXME how to find the real width (in pt/mm/inch) ?
02001 unsigned ColInfoRecord::width() const
02002 {
02003   return d->width;
02004 }
02005 
02006 void ColInfoRecord::setWidth( unsigned w )
02007 {
02008   d->width = w;
02009 }
02010 
02011 unsigned ColInfoRecord::xfIndex() const
02012 {
02013   return d->xfIndex;
02014 }
02015 
02016 void ColInfoRecord::setXfIndex( unsigned i )
02017 {
02018   d->xfIndex = i;
02019 }
02020 
02021 bool ColInfoRecord::hidden() const
02022 {
02023   return d->hidden;
02024 }
02025 
02026 void ColInfoRecord::setHidden( bool h )
02027 {
02028   d->hidden = h;
02029 }
02030 
02031 bool ColInfoRecord::collapsed() const
02032 {
02033   return d->collapsed;
02034 }
02035 
02036 void ColInfoRecord::setCollapsed( bool c )
02037 {
02038   d->collapsed = c;
02039 }
02040 
02041 unsigned ColInfoRecord::outlineLevel() const
02042 {
02043   return d->outlineLevel;
02044 }
02045 
02046 void ColInfoRecord::setOutlineLevel( unsigned l )
02047 {
02048   d->outlineLevel = l;
02049 }
02050 
02051 void ColInfoRecord::setData( unsigned size, const unsigned char* data )
02052 {
02053   if( size < 10 ) return;
02054 
02055   setFirstColumn( readU16( data ) );
02056   setLastColumn( readU16( data+2 ) );
02057   setWidth( readU16( data+4 ) );
02058   setXfIndex( readU16( data+6 ) );
02059   
02060   unsigned options = readU16( data+8 );
02061   setHidden ( options & 1 );
02062   setCollapsed ( options & 0x1000 );
02063   setOutlineLevel( ( options >> 8 ) & 7 );
02064 }
02065 
02066 void ColInfoRecord::dump( std::ostream& out ) const
02067 {
02068   out << "COLINFO" << std::endl;
02069   out << "       First Column : " << firstColumn() << std::endl;
02070   out << "        Last Column : " << lastColumn() << std::endl;
02071   out << "              Width : " << width() << std::endl;
02072   out << "           XF Index : " << xfIndex() << std::endl;
02073   out << "             Hidden : " << ( hidden() ? "Yes" : "No" ) << std::endl;
02074   out << "          Collapsed : " << ( collapsed() ? "Yes" : "No" ) << std::endl;
02075   out << "      Outline Level : " << outlineLevel() << std::endl;  
02076 }
02077 
02078 // ========== DATEMODE ========== 
02079 
02080 const unsigned int DateModeRecord::id = 0x0022;
02081 
02082 class DateModeRecord::Private
02083 {
02084 public:
02085   bool base1904;
02086 };
02087 
02088 DateModeRecord::DateModeRecord():
02089   Record()
02090 {
02091   d = new DateModeRecord::Private();
02092   d->base1904 = false;
02093 }
02094 
02095 DateModeRecord::~DateModeRecord()
02096 {
02097   delete d;
02098 }
02099 
02100 bool DateModeRecord::base1904() const
02101 {
02102   return d->base1904;
02103 }
02104 
02105 void DateModeRecord::setBase1904( bool r )
02106 {
02107   d->base1904 = r;
02108 }
02109 
02110 void DateModeRecord::setData( unsigned size, const unsigned char* data )
02111 {
02112   if( size < 2 ) return;
02113   
02114   unsigned flag = readU16( data );
02115   d->base1904 = flag != 0;
02116 }
02117 
02118 void DateModeRecord::dump( std::ostream& out ) const
02119 {
02120   out << "DATEMODE" << std::endl;
02121   out << "          1904 base : " << (base1904() ? "Yes" : "No") << std::endl;
02122 }
02123 
02124 
02125 // ========== DIMENSION ========== 
02126 
02127 const unsigned int DimensionRecord::id = 0x0200;
02128 
02129 class DimensionRecord::Private
02130 {
02131 public:
02132   unsigned firstRow;
02133   unsigned lastRow;
02134   unsigned firstColumn;
02135   unsigned lastColumn;
02136 };
02137 
02138 DimensionRecord::DimensionRecord():
02139   Record()
02140 {
02141   d = new DimensionRecord::Private;
02142   d->firstRow    = 0;
02143   d->lastRow     = 0;
02144   d->firstColumn = 0;
02145   d->lastColumn  = 0;
02146 }
02147 
02148 DimensionRecord::~DimensionRecord()
02149 {
02150   delete d;
02151 }
02152 
02153 unsigned DimensionRecord::firstRow() const
02154 {
02155   return d->firstRow;
02156 }
02157 
02158 void DimensionRecord::setFirstRow( unsigned r )
02159 {
02160   d->firstRow = r;
02161 }
02162 
02163 unsigned DimensionRecord::lastRow() const
02164 {
02165   return d->lastRow;
02166 }
02167 
02168 void DimensionRecord::setLastRow( unsigned r )
02169 {
02170   d->lastRow = r;
02171 }
02172 
02173 unsigned DimensionRecord::firstColumn() const
02174 {
02175   return d->firstColumn;
02176 }
02177 
02178 void DimensionRecord::setFirstColumn( unsigned r )
02179 {
02180   d->firstColumn = r;
02181 }
02182 
02183 unsigned DimensionRecord::lastColumn() const
02184 {
02185   return d->lastColumn;
02186 }
02187 
02188 void DimensionRecord::setLastColumn( unsigned r )
02189 {
02190   d->lastColumn = r;
02191 }
02192 
02193 void DimensionRecord::setData( unsigned size, const unsigned char* data )
02194 {
02195   if( size < 14 ) return;
02196   
02197   setFirstRow( readU32( data ) );
02198   setLastRow( readU32( data+4 ) - 1 );
02199   setFirstColumn( readU16( data + 8 ) );
02200   setLastColumn( readU16( data + 10 ) - 1 );
02201 }
02202 
02203 void DimensionRecord::dump( std::ostream& out ) const
02204 {
02205   out << "DIMENSION" << std::endl;
02206   out << "          First Row : " << firstRow() << std::endl;
02207   out << "           Last Row : " << lastRow() << std::endl;
02208   out << "       First Column : " << firstColumn() << std::endl;
02209   out << "        Last Column : " << lastColumn() << std::endl;
02210 }
02211 
02212 // ========== EOF ========== 
02213 
02214 const unsigned int EOFRecord::id = 0x000a;
02215 
02216 EOFRecord::EOFRecord():
02217   Record()
02218 {
02219 }
02220 
02221 EOFRecord::~EOFRecord()
02222 {
02223 }
02224 
02225 void EOFRecord::setData( unsigned,  const unsigned char* )
02226 {
02227   // no data associated with EOF record
02228 }
02229 
02230 void EOFRecord::dump( std::ostream& out ) const
02231 {
02232   out << "EOF" << std::endl;
02233 }
02234 
02235 // ========== EXTERNNAME ========== 
02236 
02237 const unsigned int ExternNameRecord::id = 0x0023;
02238 
02239 class ExternNameRecord::Private
02240 {
02241 public:
02242   unsigned optionFlags;
02243   unsigned sheetIndex;   // one-based, not zero-based
02244   UString externName;
02245 };
02246 
02247 
02248 ExternNameRecord::ExternNameRecord()
02249 {
02250   d = new Private;
02251   d->optionFlags = 0;
02252   d->sheetIndex = 0;
02253 }
02254 
02255 ExternNameRecord::~ExternNameRecord()
02256 {
02257   delete d;
02258 }
02259 
02260 void ExternNameRecord::setSheetIndex( unsigned sheetIndex )
02261 {
02262   d->sheetIndex = sheetIndex;
02263 }
02264 
02265 unsigned ExternNameRecord::sheetIndex() const
02266 {
02267   return d->sheetIndex;
02268 }
02269 
02270 void ExternNameRecord::setExternName( const UString& name )
02271 {
02272   d->externName = name;
02273 }
02274 
02275 UString ExternNameRecord::externName() const
02276 {
02277   return d->externName;
02278 }
02279 
02280 void ExternNameRecord::setData( unsigned size, const unsigned char* data )
02281 {
02282   if( size < 6 ) return;
02283   
02284   if ( version() == Excel97 )
02285   {
02286     d->optionFlags = readU16( data );
02287     d->sheetIndex = readU16( data+2 );
02288     d->externName = EString::fromUnicodeString( data+6, false, size ).str();
02289   }
02290 
02291   if ( version() == Excel95 )
02292   {
02293     d->optionFlags = 0;
02294     d->sheetIndex = 0;
02295     d->externName = EString::fromByteString( data+6, false, size ).str();
02296   }
02297 }
02298 
02299 void ExternNameRecord::dump( std::ostream& out ) const
02300 {
02301 }
02302 
02303 // ========== FILEPASS ========== 
02304 
02305 const unsigned int FilepassRecord::id = 0x002f;
02306 
02307 FilepassRecord::FilepassRecord():
02308   Record()
02309 {
02310 }
02311 
02312 FilepassRecord::~FilepassRecord()
02313 {
02314 }
02315 
02316 void FilepassRecord::setData( unsigned,  const unsigned char* )
02317 {
02318   // TODO
02319 }
02320 
02321 void FilepassRecord::dump( std::ostream& out ) const
02322 {
02323   out << "FILEPASS" << std::endl;
02324 }
02325 
02326 // ========== FONT ========== 
02327 
02328 const unsigned int FontRecord::id = 0x0031;
02329 
02330 class FontRecord::Private
02331 {
02332 public:
02333   unsigned height;
02334   UString fontName;
02335   unsigned fontFamily;
02336   unsigned characterSet;
02337   unsigned colorIndex;
02338   unsigned boldness;
02339   bool italic;
02340   bool strikeout;
02341   unsigned escapement;
02342   unsigned underline;
02343 };
02344 
02345 FontRecord::FontRecord():  Record()
02346 {
02347   d = new FontRecord::Private;
02348   d->height       = 11;
02349   d->fontName     = "Arial";
02350   d->fontFamily   = 0;
02351   d->characterSet = 0;
02352   d->colorIndex   = 0;
02353   d->boldness     = 400;
02354   d->italic       = false;
02355   d->strikeout    = false;
02356   d->escapement   = Normal;
02357   d->underline    = None;
02358 }
02359 
02360 FontRecord::~FontRecord()
02361 {
02362   delete d;
02363 }
02364 
02365 FontRecord::FontRecord( const FontRecord& ef ):  Record()
02366 {
02367   d = new FontRecord::Private;
02368   operator=( ef );
02369 }
02370 
02371 FontRecord& FontRecord::operator=( const FontRecord& ef )
02372 {
02373   d->height       = ef.height();
02374   d->fontName     = ef.fontName();
02375   d->fontFamily   = ef.fontFamily();
02376   d->characterSet = ef.characterSet();
02377   d->boldness     = ef.boldness();
02378   d->italic       = ef.italic();
02379   d->strikeout    = ef.strikeout();
02380   d->escapement   = ef.escapement();
02381   d->underline    = ef.underline();
02382   d->colorIndex   = ef.colorIndex();
02383   return *this;
02384 }
02385 
02386 unsigned FontRecord::height() const
02387 {
02388   return d->height;
02389 }
02390 
02391 void FontRecord::setHeight( unsigned h )
02392 {
02393   d->height = h;
02394 }
02395 
02396 UString FontRecord::fontName() const
02397 {
02398   return d->fontName;
02399 }
02400 
02401 void FontRecord::setFontName( const UString& fn )
02402 {
02403   d->fontName = fn;
02404 }
02405 
02406 unsigned FontRecord::fontFamily() const
02407 {
02408   return d->fontFamily;
02409 }
02410 
02411 void FontRecord::setFontFamily( unsigned f )
02412 {
02413   d->fontFamily = f;
02414 }
02415 
02416 unsigned FontRecord::characterSet() const
02417 {
02418   return d->characterSet;
02419 }
02420 
02421 void FontRecord::setCharacterSet( unsigned cs )
02422 {
02423   d->characterSet = cs;
02424 }
02425 
02426 unsigned FontRecord::colorIndex() const
02427 {
02428   return d->colorIndex;
02429 }
02430 
02431 void FontRecord::setColorIndex( unsigned ci )
02432 {
02433   d->colorIndex = ci;
02434 }
02435 
02436 unsigned FontRecord::boldness() const
02437 {
02438   return d->boldness;
02439 }
02440 
02441 void FontRecord::setBoldness( unsigned b )
02442 {
02443   d->boldness = b;
02444 }
02445 
02446 bool FontRecord::italic() const
02447 {
02448   return d->italic;
02449 }
02450 
02451 void FontRecord::setItalic( bool i )
02452 {
02453   d->italic = i;
02454 }
02455 
02456 bool FontRecord::strikeout() const
02457 {
02458   return d->strikeout;
02459 }
02460 
02461 void FontRecord::setStrikeout( bool s )
02462 {
02463   d->strikeout = s;
02464 }
02465 
02466 unsigned FontRecord::escapement() const
02467 {
02468   return d->escapement;
02469 }
02470 
02471 void FontRecord::setEscapement( unsigned s )
02472 {
02473   d->escapement = s;
02474 }
02475 
02476 unsigned FontRecord::underline() const
02477 {
02478   return d->underline;
02479 }
02480 
02481 void FontRecord::setUnderline( unsigned u )
02482 {
02483   d->underline = u;
02484 }
02485 
02486 
02487 void FontRecord::setData( unsigned size, const unsigned char* data )
02488 {
02489   if( size < 14 ) return;
02490   
02491   setHeight( readU16( data ) );
02492   unsigned flag = readU16( data+2 );
02493   setItalic( flag & 2 );
02494   setStrikeout( flag & 8 );
02495   setStrikeout( flag & 8 );
02496   
02497   setColorIndex( readU16( data+4 ) );
02498   
02499   setBoldness( readU16( data+6 ) );
02500   setEscapement( readU16( data+8 ) );
02501   setUnderline( data[10] );
02502   
02503   setFontFamily( data[11] );
02504   setCharacterSet( data[12] );
02505     
02506   UString fn = ( version() >= Excel97 ) ?
02507     EString::fromSheetName( data+14, size-14 ).str() :
02508     EString::fromByteString( data+14, false, size-14 ).str();
02509   setFontName( fn );
02510 }
02511 
02512 
02513 void FontRecord::dump( std::ostream& out ) const
02514 {
02515   out << "FONT" << std::endl;
02516   out << "             Height : " << height() << " twips" << std::endl;
02517   out << "          Font Name : " << fontName() << std::endl;
02518   out << "        Color Index : " << colorIndex() << std::endl;
02519   out << "           Boldness : " << boldness() << std::endl;
02520   out << "             Italic : " << (italic()?"Yes":"No") << std::endl;
02521   out << "          Strikeout : " << (strikeout()?"Yes":"No") << std::endl;
02522   out << "         Escapement : ";
02523   switch( escapement() )
02524   {
02525     case Normal: out << "Normal" << std::endl; break;
02526     case Subscript: out << "Subscript" << std::endl; break;
02527     case Superscript: out << "Superscript" << std::endl; break;
02528     default: out << "Unkown " << escapement() << std::endl; break;
02529   };
02530 }
02531 
02532 // ========== FOOTER ==========
02533 
02534 const unsigned int FooterRecord::id = 0x0015;
02535 
02536 class FooterRecord::Private
02537 {
02538 public:
02539   UString footer;
02540 };
02541 
02542 FooterRecord::FooterRecord():
02543   Record()
02544 {
02545   d = new FooterRecord::Private();
02546 }
02547 
02548 FooterRecord::~FooterRecord()
02549 {
02550   delete d;
02551 }
02552 
02553 UString FooterRecord::footer() const
02554 {
02555   return d->footer;
02556 }
02557 
02558 void FooterRecord::setFooter( const UString& footer )
02559 {
02560   d->footer = footer;
02561 }
02562 
02563 void FooterRecord::setData( unsigned size, const unsigned char* data )
02564 {
02565   if( size < 2 ) return;
02566 
02567   UString footer = ( version() >= Excel97 ) ?
02568     EString::fromUnicodeString( data, true, size ).str() :
02569     EString::fromByteString( data, false, size ).str();
02570   setFooter( footer );
02571 }
02572 
02573 void FooterRecord::dump( std::ostream& out ) const
02574 {
02575   out << "FOOTER" << std::endl;
02576   out << "             Footer : " << footer() << std::endl;
02577 }
02578 
02579 // ========== FORMAT ==========
02580 
02581 const unsigned int FormatRecord::id = 0x041e;
02582 
02583 class FormatRecord::Private
02584 {
02585 public:
02586   unsigned index;
02587   UString formatString;
02588 };
02589 
02590 FormatRecord::FormatRecord():
02591   Record()
02592 {
02593   d = new FormatRecord::Private;
02594   d->index = 0;
02595   d->formatString = "General";
02596 }
02597 
02598 FormatRecord::~FormatRecord()
02599 {
02600   delete d;
02601 }
02602 
02603 FormatRecord::FormatRecord( const FormatRecord& fr ):
02604   Record()
02605 {
02606   d = new FormatRecord::Private;
02607   operator=( fr );
02608 }
02609 
02610 FormatRecord& FormatRecord::operator=( const FormatRecord& fr )
02611 {
02612   d->index = fr.index();
02613   d->formatString = fr.formatString();
02614   return *this;
02615 }
02616 
02617 unsigned FormatRecord::index() const
02618 {
02619   return d->index;
02620 }
02621 
02622 void FormatRecord::setIndex( unsigned i )
02623 {
02624   d->index = i;
02625 }
02626 
02627 UString FormatRecord::formatString() const
02628 {
02629   return d->formatString;
02630 }
02631 
02632 void FormatRecord::setFormatString( const UString& fs )
02633 {
02634   d->formatString = fs;
02635 }
02636 
02637 void FormatRecord::setData( unsigned size, const unsigned char* data )
02638 {
02639   if( size < 3 ) return;
02640   
02641   setIndex( readU16( data ) );
02642 
02643   UString fs = ( version() >= Excel97 ) ? 
02644     EString::fromUnicodeString( data+2, true, size-2 ).str() :
02645     EString::fromByteString( data+2, false, size-2 ).str();
02646   setFormatString( fs );
02647 }
02648 
02649 void FormatRecord::dump( std::ostream& out ) const
02650 {
02651   out << "FORMAT" << std::endl;
02652   out << "             Index  : " << index() << std::endl;
02653   out << "      Format String : " << formatString() << std::endl;
02654 }
02655 
02656 
02657 // ========== FORMULA ========== 
02658 
02659 const unsigned int FormulaRecord::id = 0x0006;
02660 
02661 class FormulaRecord::Private
02662 {
02663 public:
02664   Value result;
02665   FormulaTokens tokens;
02666 };
02667 
02668 FormulaRecord::FormulaRecord():
02669   Record()
02670 {
02671   d = new FormulaRecord::Private();
02672 }
02673 
02674 FormulaRecord::~FormulaRecord()
02675 {
02676   delete d;
02677 }
02678 
02679 Value FormulaRecord::result() const
02680 {
02681   return d->result;
02682 }
02683 
02684 void FormulaRecord::setResult( const Value& r )
02685 {
02686   d->result = r;
02687 }
02688 
02689 FormulaTokens FormulaRecord::tokens() const
02690 {
02691   return d->tokens;
02692 }
02693 
02694 void FormulaRecord::setData( unsigned size, const unsigned char* data )
02695 {
02696   if( size < 20 ) return;
02697   
02698   setRow( readU16( data ) );
02699   setColumn( readU16( data+2 ) );
02700   setXfIndex( readU16( data+4 ) );
02701   
02702   if( readU16( data+12 ) != 0xffff )
02703   {
02704     // Floating-point 
02705     setResult( Value( readFloat64( data+6 ) ) );
02706   }
02707   else
02708   {
02709     switch( data[6] )
02710     {
02711       case 0: // string, real value in subsequent string record
02712         setResult( Value( Value::String ) );
02713         break;
02714       case 1: // boolean
02715         setResult( Value( data[8] ? true : false ) );
02716         break;
02717       case 2: // error code  
02718         setResult( errorAsValue( data[8] ) );
02719         break;
02720       case 3: // empty
02721         setResult( Value::empty() );
02722         break;
02723       default: // fallback  
02724         setResult( Value::empty() );
02725         break;
02726     };
02727   }
02728   
02729   unsigned formula_len = readU16( data+20 );
02730   
02731   // reconstruct all tokens
02732   d->tokens.clear();
02733   for( unsigned j = 22; j < size; )
02734   {
02735     unsigned ptg = data[j++];
02736     ptg = ((ptg & 0x40) ? (ptg | 0x20) : ptg) & 0x3F;
02737     FormulaToken token( ptg );
02738     token.setVersion( version() );
02739     
02740     if( token.id() == FormulaToken::String )
02741     {
02742       // find bytes taken to represent the string
02743       EString estr = (version()==Excel97) ? 
02744         EString::fromUnicodeString( data+j, false, formula_len ) :
02745         EString::fromByteString( data+j, false, formula_len );
02746       token.setData( estr.size(), data+j );
02747       j += estr.size();  
02748     }
02749     else
02750     {
02751       // normal, fixed-size token
02752       if( token.size() > 1 )
02753       {
02754         token.setData( token.size(), data+j );
02755         j += token.size();
02756       }
02757     }
02758     
02759     d->tokens.push_back( token );
02760   }  
02761 }
02762 
02763 void FormulaRecord::dump( std::ostream& out ) const
02764 {
02765   out << "FORMULA" << std::endl;
02766   out << "                Row : " << row() << std::endl;
02767   out << "             Column : " << column() << std::endl;
02768   out << "           XF Index : " << xfIndex() << std::endl;
02769   out << "             Result : " << result() << std::endl;
02770   
02771   FormulaTokens ts = tokens();
02772   out << "             Tokens : " << ts.size() << std::endl;
02773   for( unsigned i = 0; i < ts.size(); i++ )
02774     out << "                       " << ts[i]  << std::endl;
02775     
02776 }
02777 
02778 // ========== LABEL ========== 
02779 
02780 const unsigned int LabelRecord::id = 0x0204;
02781 
02782 class LabelRecord::Private
02783 {
02784 public:
02785   UString label;
02786 };
02787 
02788 LabelRecord::LabelRecord():
02789   Record(), CellInfo()
02790 {
02791   d = new LabelRecord::Private();
02792   d->label = UString::null;
02793 }
02794 
02795 LabelRecord::~LabelRecord()
02796 {
02797   delete d;
02798 }
02799 
02800 UString LabelRecord::label() const
02801 {
02802   return d->label;
02803 }
02804 
02805 void LabelRecord::setLabel( const UString& l )
02806 {
02807   d->label = l;
02808 }
02809 
02810 void LabelRecord::setData( unsigned size, const unsigned char* data )
02811 {
02812   if( size < 6 ) return;
02813 
02814   setRow( readU16( data ) );
02815   setColumn( readU16( data+2 ) );
02816   setXfIndex( readU16( data+4 ) );
02817   
02818   UString label = ( version() >= Excel97 ) ?
02819     EString::fromUnicodeString( data+6, true, size-6 ).str() :
02820     EString::fromByteString( data+6, true, size-6 ).str();
02821   setLabel( label );
02822 }
02823 
02824 void LabelRecord::dump( std::ostream& out ) const
02825 {
02826   out << "LABEL" << std::endl;
02827   out << "                Row : " << row() << std::endl;
02828   out << "             Column : " << column() << std::endl;
02829   out << "           XF Index : " << xfIndex() << std::endl;
02830   out << "              Label : " << label() << std::endl;
02831 }
02832 
02833 // ========== HEADER ==========
02834 
02835 const unsigned int HeaderRecord::id = 0x0014;
02836 
02837 class HeaderRecord::Private
02838 {
02839 public:
02840   UString header;
02841 };
02842 
02843 HeaderRecord::HeaderRecord():
02844   Record()
02845 {
02846   d = new HeaderRecord::Private();
02847 }
02848 
02849 HeaderRecord::~HeaderRecord()
02850 {
02851   delete d;
02852 }
02853 
02854 UString HeaderRecord::header() const
02855 {
02856   return d->header;
02857 }
02858 
02859 void HeaderRecord::setHeader( const UString& header )
02860 {
02861   d->header = header;
02862 }
02863 
02864 void HeaderRecord::setData( unsigned size, const unsigned char* data )
02865 {
02866   if( size < 2 ) return;
02867   
02868   UString header = ( version() >= Excel97 ) ?
02869     EString::fromUnicodeString( data, true, size ).str() :
02870     EString::fromByteString( data, false, size ).str();
02871   setHeader( header );
02872 }
02873 
02874 void HeaderRecord::dump( std::ostream& out ) const
02875 {
02876   out << "HEADER" << std::endl;
02877   out << "              Header: " << header() << std::endl;
02878 }
02879 
02880 // ========== LABELSST ========== 
02881 
02882 const unsigned int LabelSSTRecord::id = 0x00fd;
02883 
02884 class LabelSSTRecord::Private
02885 {
02886 public:
02887   unsigned sstIndex;
02888 };
02889 
02890 LabelSSTRecord::LabelSSTRecord():
02891   Record(), CellInfo()
02892 {
02893   d = new LabelSSTRecord::Private();
02894   d->sstIndex = 0;
02895 }
02896 
02897 LabelSSTRecord::~LabelSSTRecord()
02898 {
02899   delete d;
02900 }
02901 
02902 unsigned LabelSSTRecord::sstIndex() const
02903 {
02904   return d->sstIndex;
02905 }
02906 
02907 void LabelSSTRecord::setData( unsigned size, const unsigned char* data )
02908 {
02909   if( size < 10 ) return;
02910 
02911   setRow( readU16( data ) );
02912   setColumn( readU16( data+2 ) );
02913   setXfIndex( readU16( data+4 ) );
02914 
02915   d->sstIndex = readU32( data+6 );
02916 }
02917 
02918 void LabelSSTRecord::dump( std::ostream& out ) const
02919 {
02920   out << "LABELSST" << std::endl;
02921   out << "                Row : " << row() << std::endl;
02922   out << "             Column : " << column() << std::endl;
02923   out << "           XF Index : " << xfIndex() << std::endl;
02924   out << "          SST Index : " << d->sstIndex << std::endl;
02925 }
02926 
02927 // ========== LEFTMARGIN ========== 
02928 
02929 const unsigned int LeftMarginRecord::id = 0x0026;
02930 
02931 class LeftMarginRecord::Private
02932 {
02933 public:
02934   double leftMargin;
02935 };
02936 
02937 LeftMarginRecord::LeftMarginRecord():
02938   Record()
02939 {
02940   d = new LeftMarginRecord::Private();
02941   d->leftMargin = 1.0;
02942 }
02943 
02944 LeftMarginRecord::~LeftMarginRecord()
02945 {
02946   delete d;
02947 }
02948 
02949 double LeftMarginRecord::leftMargin() const
02950 {
02951   return d->leftMargin;
02952 }
02953 
02954 void LeftMarginRecord::setLeftMargin( double m )
02955 {
02956   d->leftMargin = m;
02957 }
02958 
02959 void LeftMarginRecord::setData( unsigned size, const unsigned char* data )
02960 {
02961   if( size < 8 ) return;
02962   setLeftMargin( readFloat64( data ) );
02963 }
02964 
02965 void LeftMarginRecord::dump( std::ostream& out ) const
02966 {
02967   out << "LEFTMARGIN" << std::endl;
02968   out << "        Left Margin : " << leftMargin() << " inches" << std::endl;
02969 }
02970 
02971 // ========== MERGEDCELLS ==========
02972 
02973 const unsigned int MergedCellsRecord::id = 0x00e5;
02974 
02975 class MergedInfo
02976 {
02977 public:
02978   unsigned firstRow, lastRow, firstColumn, lastColumn;
02979 };
02980 
02981 class MergedCellsRecord::Private
02982 {
02983 public:
02984   std::vector<MergedInfo> mergedCells;
02985 };
02986 
02987 MergedCellsRecord::MergedCellsRecord():
02988   Record()
02989 {
02990   d = new MergedCellsRecord::Private();
02991 }
02992 
02993 MergedCellsRecord::~MergedCellsRecord()
02994 {
02995   delete d;
02996 }
02997 
02998 unsigned MergedCellsRecord::count() const
02999 {
03000   return d->mergedCells.size();
03001 }
03002 
03003 unsigned MergedCellsRecord::firstRow( unsigned i ) const
03004 {
03005   if( i >= d->mergedCells.size() ) return 0;
03006   MergedInfo info = d->mergedCells[ i ];
03007   return info.firstRow;
03008 }
03009 
03010 unsigned MergedCellsRecord::lastRow( unsigned i ) const
03011 {
03012   if( i >= d->mergedCells.size() ) return 0;
03013   MergedInfo info = d->mergedCells[ i ];
03014   return info.lastRow;
03015 }
03016 
03017 unsigned MergedCellsRecord::firstColumn( unsigned i ) const
03018 {
03019   if( i >= d->mergedCells.size() ) return 0;
03020   MergedInfo info = d->mergedCells[ i ];
03021   return info.firstColumn;
03022 }
03023 
03024 unsigned MergedCellsRecord::lastColumn( unsigned i ) const
03025 {
03026   if( i >= d->mergedCells.size() ) return 0;
03027   MergedInfo info = d->mergedCells[ i ];
03028   return info.lastColumn;
03029 }
03030 
03031 void MergedCellsRecord::setData( unsigned size, const unsigned char* data )
03032 {
03033   if( size < 2 ) return;
03034 
03035   unsigned num = readU16( data );
03036   
03037   // sanity check
03038   if( size < 2 + num*4 ) return;
03039   
03040   unsigned p = 2;
03041   for( unsigned i = 0; i < num; i++ )
03042   {
03043     MergedInfo info;
03044     info.firstRow = readU16( data + p );
03045     info.lastRow = readU16( data + p + 2 );
03046     info.firstColumn = readU16( data + p + 4 );
03047     info.lastColumn = readU16( data + p + 6 );
03048     p += 8;
03049     d->mergedCells.push_back( info );
03050   }
03051 }
03052 
03053 void MergedCellsRecord::dump( std::ostream& out ) const
03054 {
03055   out << "MERGEDCELLS" << std::endl;
03056   out << "              Count : " << count() << std::endl;
03057   for( unsigned c = 0; c < count(); c++ )
03058   {
03059     out << "     Merged Cell #" << c << " : ";
03060     out << "Column " << firstColumn(c) << "-" << lastColumn(c);
03061     out << "   Row " << firstRow(c) << "-" << lastRow(c);
03062     out << std::endl;
03063   }
03064 }
03065 
03066 // ========== MULBLANK ==========
03067 
03068 const unsigned int MulBlankRecord::id = 0x00be;
03069 
03070 class MulBlankRecord::Private
03071 {
03072 public:
03073   std::vector<unsigned> xfIndexes;
03074 };
03075 
03076 MulBlankRecord::MulBlankRecord():
03077   Record(), CellInfo(), ColumnSpanInfo()
03078 {
03079   d = new MulBlankRecord::Private();
03080 }
03081 
03082 MulBlankRecord::~MulBlankRecord()
03083 {
03084   delete d;
03085 }
03086 
03087 void MulBlankRecord::setData( unsigned size, const unsigned char* data )
03088 {
03089   if( size < 6 ) return;
03090 
03091   setRow( readU16( data ) );
03092 
03093   setFirstColumn( readU16( data+2 ) );
03094   setLastColumn( readU16( data+size-2 ) );
03095 
03096   d->xfIndexes.clear();
03097   for( unsigned i = 4; i < size-2; i+= 2 )
03098     d->xfIndexes.push_back( readU16( data+i ) );
03099 
03100   // FIXME sentinel !
03101 }
03102 
03103 unsigned MulBlankRecord::xfIndex( unsigned i ) const
03104 {
03105   if( i >= d->xfIndexes.size() ) return 0;
03106   return d->xfIndexes[ i ];
03107 }
03108 
03109 void MulBlankRecord::dump( std::ostream& out ) const
03110 {
03111   out << "MULBLANK" << std::endl;
03112   out << "                Row : " << row() << std::endl;
03113   out << "       First Column : " << firstColumn() << std::endl;
03114   out << "        Last Column : " << lastColumn() << std::endl;
03115 }
03116 
03117 // ========== MULRK ==========
03118 
03119 const unsigned int MulRKRecord::id = 0x00bd;
03120 
03121 class MulRKRecord::Private
03122 {
03123 public:
03124   std::vector<unsigned> xfIndexes;
03125   std::vector<bool> isIntegers;
03126   std::vector<int> intValues;
03127   std::vector<double> floatValues;
03128   std::vector<unsigned> rkValues;
03129 };
03130 
03131 MulRKRecord::MulRKRecord():
03132   Record(), CellInfo(), ColumnSpanInfo()
03133 {
03134   d = new MulRKRecord::Private();
03135 }
03136 
03137 MulRKRecord::~MulRKRecord()
03138 {
03139   delete d;
03140 }
03141 
03142 unsigned MulRKRecord::xfIndex( unsigned i ) const
03143 {
03144   if( i >= d->xfIndexes.size() ) return 0;
03145   return d->xfIndexes[ i ];
03146 }
03147 
03148 bool MulRKRecord::isInteger( unsigned i ) const
03149 {
03150   if( i >= d->isIntegers.size() ) return true;
03151   return d->isIntegers[ i ];
03152 }
03153 
03154 int MulRKRecord::asInteger( unsigned i ) const
03155 {
03156   if( i >= d->intValues.size() ) return 0;
03157   return d->intValues[ i ];
03158 }
03159 
03160 double MulRKRecord::asFloat( unsigned i ) const
03161 {
03162   if( i >= d->floatValues.size() ) return 0.0;
03163   return d->floatValues[ i ];
03164 }
03165 
03166 unsigned MulRKRecord::encodedRK( unsigned i ) const
03167 {
03168   if( i >= d->rkValues.size() ) return 0;
03169   return d->rkValues[ i ];
03170 }
03171 
03172 void MulRKRecord::setData( unsigned size, const unsigned char* data )
03173 {
03174   if( size < 6 ) return;
03175 
03176   setRow( readU16( data ) );
03177 
03178   setFirstColumn( readU16( data+2 ) );
03179   setLastColumn( readU16( data+size-2 ) );
03180 
03181   d->xfIndexes.clear();
03182   d->isIntegers.clear();
03183   d->intValues.clear();
03184   d->floatValues.clear();
03185   for( unsigned i = 4; i < size-2; i+= 6 )
03186   {
03187     d->xfIndexes.push_back( readU16( data+i ) );
03188     unsigned rk = readU32( data+i+2 );
03189     d->rkValues.push_back( rk );
03190     bool isInteger = true; int iv = 0; double fv = 0.0;
03191     decodeRK( rk, isInteger, iv, fv );
03192 
03193     d->isIntegers.push_back( isInteger );
03194     d->intValues.push_back( isInteger ? iv : (int)fv );
03195     d->floatValues.push_back( !isInteger ? fv : (double)iv );
03196   }
03197 
03198   // FIXME sentinel !
03199 }
03200 
03201 void MulRKRecord::dump( std::ostream& out ) const
03202 {
03203   out << "MULRK" << std::endl;
03204   out << "                Row : " << row() << std::endl;
03205   out << "       First Column : " << firstColumn() << std::endl;
03206   out << "        Last Column : " << lastColumn() << std::endl;
03207   for( unsigned c = firstColumn(); c <= lastColumn(); c++ )
03208   {
03209     out << "          Column  " << c << " : " << asFloat( c-firstColumn() );
03210     out << "  Encoded: " << std::hex << encodedRK( c-firstColumn() );
03211     out << std::endl;
03212   }
03213 }
03214 
03215 // ========== NAME ========== 
03216 
03217 const unsigned int NameRecord::id = 0x0018;
03218 
03219 class NameRecord::Private
03220 {
03221 public:
03222   unsigned optionFlags;
03223   UString definedName;
03224 };
03225 
03226 
03227 NameRecord::NameRecord()
03228 {
03229   d = new Private;
03230   d->optionFlags = 0;
03231 }
03232 
03233 NameRecord::~NameRecord()
03234 {
03235   delete d;
03236 }
03237 
03238 void NameRecord::setDefinedName( const UString& name )
03239 {
03240   d->definedName = name;
03241 }
03242 
03243 UString NameRecord::definedName() const
03244 {
03245   return d->definedName;
03246 }
03247 
03248 void NameRecord::setData( unsigned size, const unsigned char* data )
03249 {
03250   if( size < 14 ) return;
03251   
03252   d->optionFlags = readU16( data );
03253   unsigned len = data[3];
03254 
03255   if ( version() == Excel95 )
03256   {
03257     char* buffer = new char[ len+1 ];
03258     memcpy( buffer, data + 14, len );
03259     buffer[ len ] = 0;
03260     d->definedName = UString( buffer );
03261     delete[] buffer;
03262   }
03263 
03264   if ( version() == Excel97 )
03265   {
03266     UString str = UString();
03267     for( unsigned k=0; k<len; k++ )
03268     {
03269       unsigned uchar = readU16( data + 14 + k*2 );
03270       str.append( UString(uchar) );
03271     }
03272     d->definedName = str;
03273   }
03274 }
03275 
03276 void NameRecord::dump( std::ostream& out ) const
03277 {
03278 }
03279 
03280 // ========== Number ========== 
03281 
03282 const unsigned int NumberRecord::id = 0x0203;
03283 
03284 class NumberRecord::Private
03285 {
03286 public:
03287   double number;
03288 };
03289 
03290 NumberRecord::NumberRecord():
03291   Record(), CellInfo()
03292 {
03293   d = new NumberRecord::Private();
03294   d->number = 0.0;
03295 }
03296 
03297 NumberRecord::~NumberRecord()
03298 {
03299   delete d;
03300 }
03301 
03302 double NumberRecord::number() const
03303 {
03304   return d->number;
03305 }
03306 
03307 void NumberRecord::setNumber( double f )
03308 {
03309   d->number = f;
03310 }
03311 
03312 // FIXME check that sizeof(double) is 64
03313 void NumberRecord::setData( unsigned size, const unsigned char* data )
03314 {
03315   if( size < 14 ) return;
03316 
03317   setRow( readU16( data ) );
03318   setColumn( readU16( data+2 ) );
03319   setXfIndex( readU16( data+4 ) );
03320   setNumber( readFloat64( data+6 ) );
03321 }
03322 
03323 void NumberRecord::dump( std::ostream& out ) const
03324 {
03325   out << "NUMBER" << std::endl;
03326   out << "                Row : " << row() << std::endl;
03327   out << "             Column : " << column() << std::endl;
03328   out << "           XF Index : " << xfIndex() << std::endl;
03329   out << "              Value : " << number() << std::endl;
03330 }
03331 
03332 // ========== PALETTE ========== 
03333 
03334 const unsigned int PaletteRecord::id = 0x0092;
03335 
03336 class PaletteRecord::Private
03337 {
03338 public:
03339   std::vector<Color> colors;
03340 };
03341 
03342 PaletteRecord::PaletteRecord():
03343   Record()
03344 {
03345   d = new PaletteRecord::Private();
03346 }
03347 
03348 PaletteRecord::~PaletteRecord()
03349 {
03350   delete d;
03351 }
03352 
03353 Color PaletteRecord::color( unsigned i ) const
03354 {
03355   return d->colors[ i ];
03356 }
03357 
03358 unsigned PaletteRecord::count() const
03359 {
03360   return d->colors.size();
03361 }
03362 
03363 void PaletteRecord::setData( unsigned size, const unsigned char* data )
03364 {
03365   if( size < 14 ) return;
03366   
03367   unsigned num = readU16( data );
03368   
03369   unsigned p = 2;
03370   for( unsigned i = 0; i < num; i++, p+=4 )
03371   {
03372     unsigned red = data[ p ];
03373     unsigned green = data[ p+1 ];
03374     unsigned blue = data[ p+2 ];
03375     d->colors.push_back( Color( red, green, blue ) );
03376   }
03377 }
03378 
03379 void PaletteRecord::dump( std::ostream& out ) const
03380 {
03381   out << "PALETTE" << std::endl;
03382   out << "             Count : " << count() << std::endl;
03383   for( unsigned i = 0; i < count(); i++ )
03384   {
03385     out << "         Color #" << std::setw(2) << i << " : ";
03386     Color c = color( i );
03387     out << "R:" << std::setw(3) << c.red;
03388     out << "   G:" << std::setw(3) << c.green;
03389     out << "   B:" << std::setw(3) << c.blue << std::endl;
03390   }
03391 }
03392 
03393 // ========== RIGHTMARGIN ========== 
03394 
03395 const unsigned int RightMarginRecord::id = 0x0027;
03396 
03397 class RightMarginRecord::Private
03398 {
03399 public:
03400   double rightMargin;
03401 };
03402 
03403 RightMarginRecord::RightMarginRecord():
03404   Record()
03405 {
03406   d = new RightMarginRecord::Private();
03407   d->rightMargin = 1.0;
03408 }
03409 
03410 RightMarginRecord::~RightMarginRecord()
03411 {
03412   delete d;
03413 }
03414 
03415 double RightMarginRecord::rightMargin() const
03416 {
03417   return d->rightMargin;
03418 }
03419 
03420 void RightMarginRecord::setRightMargin( double m )
03421 {
03422   d->rightMargin = m;
03423 }
03424 
03425 void RightMarginRecord::setData( unsigned size, const unsigned char* data )
03426 {
03427   if( size < 8 ) return;
03428   setRightMargin( readFloat64( data ) );
03429 }
03430 
03431 void RightMarginRecord::dump( std::ostream& out ) const
03432 {
03433   out << "RIGHTMARGIN" << std::endl;
03434   out << "       Right Margin : " << rightMargin() << " inches " << std::endl;
03435 }
03436 
03437 // ========== RK ==========
03438 
03439 const unsigned int RKRecord::id = 0x027e;
03440 
03441 class RKRecord::Private
03442 {
03443 public:
03444   bool integer;
03445   unsigned rk;
03446   int i;
03447   double f;
03448 };
03449 
03450 RKRecord::RKRecord():
03451   Record(), CellInfo()
03452 {
03453   d = new RKRecord::Private();
03454   d->integer = true;
03455   d->rk = 0;
03456   d->i = 0;
03457   d->f = 0.0;
03458 }
03459 
03460 RKRecord::~RKRecord()
03461 {
03462   delete d;
03463 }
03464 
03465 bool RKRecord::isInteger() const
03466 {
03467   return d->integer;
03468 }
03469 
03470 bool RKRecord::isFloat() const
03471 {
03472   return !d->integer;
03473 }
03474 
03475 int RKRecord::asInteger() const
03476 {
03477   if( d->integer )
03478     return d->i;
03479   else
03480     return (int)d->f;
03481 }
03482 
03483 double RKRecord::asFloat() const
03484 {
03485   if( !d->integer )
03486     return d->f;
03487   else
03488     return (double)d->i;
03489 }
03490 
03491 void RKRecord::setInteger( int i )
03492 {
03493   d->integer = true;
03494   d->i = i;
03495   d->f = (double)i;
03496 }
03497 
03498 void RKRecord::setFloat( double f )
03499 {
03500   d->integer = false;
03501   d->i = (int)f;
03502   d->f = f;
03503 }
03504 
03505 unsigned RKRecord::encodedRK() const
03506 {
03507   return d->rk;
03508 }
03509 
03510 // FIXME check sizeof(int) is 32
03511 // big vs little endian problem
03512 void RKRecord::setData( unsigned size, const unsigned char* data )
03513 {
03514   if( size < 10 ) return;
03515 
03516   setRow( readU16( data ) );
03517   setColumn( readU16( data+2 ) );
03518   setXfIndex( readU16( data+4 ) );
03519 
03520   int i = 0; double f = 0.0;
03521   d->rk = readU32( data+6 );
03522   decodeRK( d->rk, d->integer, i, f );
03523   if( d->integer ) setInteger( i );
03524   else setFloat( f );
03525 }
03526 
03527 void RKRecord::dump( std::ostream& out ) const
03528 {
03529   out << "RK" << std::endl;
03530   out << "                Row : " << row() << std::endl;
03531   out << "             Column : " << column() << std::endl;
03532   out << "           XF Index : " << xfIndex() << std::endl;
03533   out << "              Value : " << asFloat() << std::endl;
03534   out << "         Encoded RK : 0x" << std::hex << encodedRK() << std::endl;
03535   out << std::dec;
03536 }
03537 
03538 // ========== Row ==========
03539 
03540 const unsigned int RowRecord::id = 0x0208;
03541 
03542 class RowRecord::Private
03543 {
03544 public:
03545   unsigned row;
03546   unsigned height;
03547   unsigned xfIndex;
03548   bool hidden;
03549 };
03550 
03551 RowRecord::RowRecord():
03552   Record(), ColumnSpanInfo()
03553 {
03554   d = new RowRecord::Private();
03555   d->row     = 0;
03556   d->height  = 50;
03557   d->xfIndex = 0;
03558   d->hidden  = false;
03559 }
03560 
03561 RowRecord::~RowRecord()
03562 {
03563   delete d;
03564 }
03565 
03566 unsigned RowRecord::row() const
03567 {
03568   return d->row;
03569 }
03570 
03571 void RowRecord::setRow( unsigned r )
03572 {
03573   d->row = r;
03574 }
03575 
03576 unsigned RowRecord::height() const
03577 {
03578   return d->height;
03579 }
03580 
03581 void RowRecord::setHeight( unsigned h )
03582 {
03583   d->height = h;
03584 }
03585 
03586 unsigned RowRecord::xfIndex() const
03587 {
03588   return d->xfIndex;
03589 }
03590 
03591 void RowRecord::setXfIndex( unsigned i )
03592 {
03593   d->xfIndex = i;
03594 }
03595 
03596 bool RowRecord::hidden() const
03597 {
03598   return d->hidden;
03599 }
03600 
03601 void RowRecord::setHidden( bool h )
03602 {
03603   d->hidden = h;
03604 }
03605 
03606 void RowRecord::setData( unsigned size, const unsigned char* data )
03607 {
03608   if( size < 16 ) return;
03609   
03610   setRow( readU16( data ) );
03611   setFirstColumn( readU16( data+2 ) );
03612   setLastColumn( readU16( data+4 ) );
03613   setHeight( readU16( data+6 ) & 0x7fff );
03614   setXfIndex( readU16( data+14 ) & 0xfff );
03615   
03616   unsigned options = readU16( data+12 );
03617   setHidden ( options & 0x20 );
03618 }
03619 
03620 void RowRecord::dump( std::ostream& out ) const
03621 {
03622   out << "ROW" << std::endl;
03623   out << "                Row : " << row() << std::endl;
03624   out << "       First Column : " << firstColumn() << std::endl;
03625   out << "        Last Column : " << lastColumn() << std::endl;
03626   out << "             Height : " << height() << std::endl;
03627   out << "           XF Index : " << xfIndex() << std::endl;
03628   out << "             Hidden : " << ( hidden() ? "Yes" : "No" ) << std::endl;
03629 }
03630 
03631 // ========== RSTRING ========== 
03632 
03633 const unsigned int RStringRecord::id = 0x00d6;
03634 
03635 class RStringRecord::Private
03636 {
03637 public:
03638   UString label;
03639 };
03640 
03641 RStringRecord::RStringRecord():
03642   Record(), CellInfo()
03643 {
03644   d = new RStringRecord::Private();
03645   d->label = UString::null;
03646 }
03647 
03648 RStringRecord::~RStringRecord()
03649 {
03650   delete d;
03651 }
03652 
03653 UString RStringRecord::label() const
03654 {
03655   return d->label;
03656 }
03657 
03658 void RStringRecord::setLabel( const UString& l )
03659 {
03660   d->label = l;
03661 }
03662 
03663 // FIXME formatting runs ? in EString perhaps ?
03664 void RStringRecord::setData( unsigned size, const unsigned char* data )
03665 {
03666   if( size < 6 ) return;
03667 
03668   setRow( readU16( data ) );
03669   setColumn( readU16( data+2 ) );
03670   setXfIndex( readU16( data+4 ) );
03671   
03672   // FIXME check Excel97
03673   UString label = ( version() >= Excel97 ) ?
03674     EString::fromUnicodeString( data+6, true, size-6 ).str() :
03675     EString::fromByteString( data+6, true, size-6 ).str();
03676   setLabel( label );
03677 }
03678 
03679 void RStringRecord::dump( std::ostream& out ) const
03680 {
03681   out << "RSTRING" << std::endl;
03682   out << "                Row : " << row() << std::endl;
03683   out << "             Column : " << column() << std::endl;
03684   out << "           XF Index : " << xfIndex() << std::endl;
03685   out << "              Label : " << label() << std::endl;
03686 }
03687 
03688 // ========== SST ==========
03689 
03690 const unsigned int SSTRecord::id = 0x00fc;
03691 
03692 class SSTRecord::Private
03693 {
03694 public:
03695   unsigned total;
03696   unsigned count;  
03697   std::vector<UString> strings;
03698 };
03699 
03700 SSTRecord::SSTRecord():
03701   Record()
03702 {
03703   d = new SSTRecord::Private();
03704   d->total = 0;
03705   d->count = 0;
03706 }
03707 
03708 SSTRecord::~SSTRecord()
03709 {
03710   delete d;
03711 }
03712 
03713 UString sstrecord_get_plain_string( const unsigned char* data, unsigned length )
03714 {
03715   char* buffer = new char[ length+1 ];
03716   memcpy( buffer, data, length );
03717   buffer[ length ] = 0;
03718   UString str = UString( buffer );
03719   delete[] buffer;
03720   return str;
03721 }
03722 
03723 void SSTRecord::setData( unsigned size, const unsigned char* data )
03724 {
03725   if( size < 8 ) return;
03726   
03727   d->total = readU32( data );
03728   d->count = readU32( data+4 );
03729   
03730   unsigned offset = 8;
03731   d->strings.clear();
03732   
03733   for( unsigned i = 0; i < d->count; i++ )
03734   {
03735     // check against size
03736     if (offset >= size) {
03737       std::cerr << "Warning: reached end of SST record, but not all strings have been read!" << std::endl;
03738       break;
03739     }
03740     
03741     EString es = EString::fromUnicodeString( data+offset, true, size - offset );
03742     d->strings.push_back( es.str() );
03743     offset += es.size();
03744   }
03745 
03746   
03747   // sanity check, adjust to safer condition
03748   if( d->count < d->strings.size() )
03749   {
03750     std::cerr << "Warning: mismatch number of string in SST record!" << std::endl;
03751     d->count = d->strings.size();
03752   }
03753 }
03754 
03755 unsigned SSTRecord::count() const
03756 {
03757   return d->count;
03758 }
03759 
03760 // why not just string() ? to avoid easy confusion with std::string
03761 UString SSTRecord::stringAt( unsigned index ) const
03762 {
03763   if( index >= count()) return UString::null;
03764   return d->strings[ index ];
03765 }
03766 
03767 void SSTRecord::dump( std::ostream& out ) const
03768 {
03769   out << "SST" << std::endl;
03770   out << "         Occurences : " << d->total << std::endl;
03771   out << "              Count : " << count() << std::endl;
03772   for( unsigned i = 0; i < count(); i++ )
03773     out << "         String #" << std::setw(2) << i << " : " << 
03774     stringAt( i ) << std::endl;
03775 }
03776 
03777 // ========== STRING ==========
03778 
03779 const unsigned int StringRecord::id = 0x0207;
03780 
03781 class StringRecord::Private
03782 {
03783 public:
03784   UString string;
03785 };
03786 
03787 StringRecord::StringRecord():
03788   Record()
03789 {
03790   d = new StringRecord::Private();
03791 }
03792 
03793 StringRecord::~StringRecord()
03794 {
03795   delete d;
03796 }
03797 
03798 void StringRecord::setData( unsigned size, const unsigned char* data )
03799 {
03800   if( size < 3 ) return;
03801   
03802   //  TODO simple string for BIFF7
03803   
03804   EString es = EString::fromUnicodeString( data, true, size );
03805   d->string = es.str();
03806 }
03807 
03808 UString StringRecord::ustring() const
03809 {
03810   return d->string;
03811 }
03812 
03813 Value StringRecord::value() const
03814 {
03815   return Value( d->string );
03816 }  
03817 
03818 void StringRecord::dump( std::ostream& out ) const
03819 {
03820   out << "STRING" << std::endl;
03821   out << "             String : " << ustring() << std::endl;
03822 }
03823 
03824 
03825 // ========== TOPMARGIN ==========
03826 
03827 const unsigned int TopMarginRecord::id = 0x0028;
03828 
03829 class TopMarginRecord::Private
03830 {
03831 public:
03832   double topMargin;
03833 };
03834 
03835 TopMarginRecord::TopMarginRecord():
03836   Record()
03837 {
03838   d = new TopMarginRecord::Private();
03839   d->topMargin = 1.0;
03840 }
03841 
03842 TopMarginRecord::~TopMarginRecord()
03843 {
03844   delete d;
03845 }
03846 
03847 double TopMarginRecord::topMargin() const
03848 {
03849   return d->topMargin;
03850 }
03851 
03852 void TopMarginRecord::setTopMargin( double m )
03853 {
03854   d->topMargin = m;
03855 }
03856 
03857 void TopMarginRecord::setData( unsigned size, const unsigned char* data )
03858 {
03859   if( size < 8 ) return;
03860   setTopMargin( readFloat64( data ) );
03861 }
03862 
03863 void TopMarginRecord::dump( std::ostream& out ) const
03864 {
03865   out << "TOPMARGIN" << std::endl;
03866   out << "         Top Margin : " << topMargin() << " inches " << std::endl;
03867 }
03868 
03869 // ========== XF ==========
03870 
03871 const unsigned int XFRecord::id = 0x00e0;
03872 
03873 class XFRecord::Private
03874 {
03875 public:
03876   unsigned fontIndex;
03877   unsigned formatIndex;
03878   bool locked;
03879   bool formulaHidden;
03880   unsigned parentStyle;
03881   unsigned horizontalAlignment;
03882   unsigned verticalAlignment;
03883   bool textWrap;
03884   unsigned rotationAngle;
03885   bool stackedLetters;
03886   unsigned indentLevel;
03887   bool shrinkContent;
03888   unsigned leftBorderStyle;
03889   unsigned leftBorderColor;
03890   unsigned rightBorderStyle;
03891   unsigned rightBorderColor;
03892   unsigned topBorderStyle;
03893   unsigned topBorderColor;
03894   unsigned bottomBorderStyle;
03895   unsigned bottomBorderColor;
03896   bool diagonalTopLeft;
03897   bool diagonalBottomLeft;
03898   unsigned diagonalStyle;
03899   unsigned diagonalColor;
03900   unsigned fillPattern;
03901   unsigned patternForeColor;
03902   unsigned patternBackColor;
03903 };
03904 
03905 XFRecord::XFRecord():  Record()
03906 {
03907   d = new XFRecord::Private();
03908   d->fontIndex           = 0;
03909   d->formatIndex         = 0;
03910   d->locked              = false;
03911   d->formulaHidden       = false;
03912   d->parentStyle         = 0;
03913   d->horizontalAlignment = Left;
03914   d->verticalAlignment   = VCentered;
03915   d->textWrap            = false;
03916   d->rotationAngle       = 0;
03917   d->stackedLetters      = 0;
03918   d->indentLevel         = 0;
03919   d->shrinkContent       = 0;
03920   d->leftBorderStyle     = 0;
03921   d->leftBorderColor     = 0;
03922   d->rightBorderStyle    = 0;
03923   d->rightBorderColor    = 0;
03924   d->topBorderStyle      = 0;
03925   d->topBorderColor      = 0;
03926   d->bottomBorderStyle   = 0;
03927   d->bottomBorderColor   = 0;
03928   d->diagonalTopLeft     = false;
03929   d->diagonalBottomLeft  = false;
03930   d->diagonalStyle       = 0;
03931   d->diagonalColor       = 0;
03932   d->fillPattern         = 0;
03933   d->patternForeColor    = 0;
03934   d->patternBackColor    = 0;
03935 }
03936 
03937 XFRecord::~XFRecord()
03938 {
03939   delete d;
03940 }
03941 
03942 XFRecord::XFRecord( const XFRecord& xf ):  Record()
03943 {
03944   d = new XFRecord::Private();
03945   operator=( xf );
03946 }
03947 
03948 XFRecord& XFRecord::operator=( const XFRecord& xf )
03949 {
03950   d->fontIndex           = xf.fontIndex();
03951   d->formatIndex         = xf.formatIndex();
03952   d->locked              = xf.locked();
03953   d->formulaHidden       = xf.formulaHidden();
03954   d->parentStyle         = xf.parentStyle();
03955   d->horizontalAlignment = xf.horizontalAlignment();
03956   d->verticalAlignment   = xf.verticalAlignment();
03957   d->textWrap            = xf.textWrap();
03958   d->rotationAngle       = xf.rotationAngle();
03959   d->stackedLetters      = xf.stackedLetters();
03960   d->indentLevel         = xf.indentLevel();
03961   d->shrinkContent       = xf.shrinkContent();
03962   d->leftBorderStyle     = xf.leftBorderStyle();
03963   d->leftBorderColor     = xf.leftBorderColor();
03964   d->rightBorderStyle    = xf.rightBorderStyle();
03965   d->rightBorderColor    = xf.rightBorderColor();
03966   d->topBorderStyle      = xf.topBorderStyle();
03967   d->topBorderColor      = xf.topBorderColor();
03968   d->bottomBorderStyle   = xf.bottomBorderStyle();
03969   d->bottomBorderColor   = xf.bottomBorderColor();
03970   d->diagonalTopLeft     = xf.diagonalTopLeft();
03971   d->diagonalBottomLeft  = xf.diagonalBottomLeft();
03972   d->diagonalStyle       = xf.diagonalStyle();
03973   d->diagonalColor       = xf.diagonalColor();
03974   d->fillPattern         = xf.fillPattern();
03975   d->patternForeColor    = xf.patternForeColor();
03976   d->patternBackColor    = xf.patternBackColor();
03977   return *this;
03978 }
03979 
03980 unsigned XFRecord::fontIndex() const
03981 {
03982   return d->fontIndex;
03983 }
03984 
03985 void XFRecord::setFontIndex( unsigned fi )
03986 {
03987   d->fontIndex = fi;
03988 }
03989 
03990 unsigned XFRecord::formatIndex() const
03991 {
03992   return d->formatIndex;
03993 }
03994 
03995 void XFRecord::setFormatIndex( unsigned fi )
03996 {
03997   d->formatIndex = fi;
03998 }
03999 
04000 bool XFRecord::locked() const
04001 {
04002   return d->locked;
04003 }
04004 
04005 void XFRecord::setLocked( bool l )
04006 {
04007   d->locked = l;
04008 }
04009 
04010 bool XFRecord::formulaHidden() const
04011 {
04012   return d->formulaHidden;
04013 }
04014 
04015 void XFRecord::setFormulaHidden( bool f )
04016 {
04017   d->formulaHidden = f;
04018 }
04019 
04020 unsigned XFRecord::parentStyle() const
04021 {
04022   return d->parentStyle;
04023 }
04024 
04025 void XFRecord::setParentStyle( unsigned p )
04026 {
04027   d->parentStyle = p;
04028 }
04029 
04030 unsigned XFRecord::horizontalAlignment() const
04031 {
04032   return d->horizontalAlignment;
04033 }
04034 
04035 void XFRecord::setHorizontalAlignment( unsigned ha )
04036 {
04037   d->horizontalAlignment = ha;
04038 }
04039 
04040 const char* XFRecord::horizontalAlignmentAsString() const
04041 {
04042   const char *result = "Unknown";
04043   switch( horizontalAlignment() )
04044   {
04045     case General:   result = "General"; break;
04046     case Left:      result = "Left"; break;
04047     case Centered:  result = "Centered"; break;
04048     case Right:     result = "Right"; break;
04049     case Justified: result = "Justified"; break;
04050     case Filled:    result = "Filled"; break;
04051     default: break;
04052   }
04053   return result;
04054 }
04055 
04056 unsigned XFRecord::verticalAlignment() const
04057 {
04058   return d->verticalAlignment;
04059 }
04060 
04061 void XFRecord::setVerticalAlignment( unsigned va )
04062 {
04063   d->verticalAlignment = va;
04064 }
04065 
04066 const char* XFRecord::verticalAlignmentAsString() const
04067 {
04068   const char *result = "Unknown";
04069   switch( verticalAlignment() )
04070   {
04071     case Top:          result = "Top"; break;
04072     case VCentered:    result = "Centered"; break;
04073     case Bottom:       result = "Bottom"; break;
04074     case VJustified:   result = "Justified"; break;
04075     case VDistributed: result = "Distributed"; break;
04076     default: break;
04077   }
04078   return result;
04079 }
04080 
04081 bool XFRecord::textWrap() const
04082 {
04083   return d->textWrap;
04084 }
04085 
04086 void XFRecord::setTextWrap( bool wrap )
04087 {
04088   d->textWrap = wrap;
04089 }
04090 
04091 unsigned XFRecord::rotationAngle() const
04092 {
04093   return d->rotationAngle;
04094 }
04095 
04096 void XFRecord::setRotationAngle( unsigned angle )
04097 {
04098   d->rotationAngle = angle;
04099 }
04100 
04101 bool XFRecord::stackedLetters() const
04102 {
04103   return d->stackedLetters;
04104 }
04105 
04106 void XFRecord::setStackedLetters( bool stacked )
04107 {
04108   d->stackedLetters = stacked;
04109 }
04110 
04111 unsigned XFRecord::indentLevel() const
04112 {
04113   return d->indentLevel;
04114 }
04115 
04116 void XFRecord::setIndentLevel( unsigned i )
04117 {
04118   d->indentLevel = i;
04119 }
04120 
04121 bool XFRecord::shrinkContent() const
04122 {
04123   return d->shrinkContent;
04124 }
04125 
04126 void XFRecord::setShrinkContent( bool s )
04127 {
04128   d->shrinkContent = s;
04129 }
04130 
04131 unsigned XFRecord::leftBorderStyle() const
04132 {
04133   return d->leftBorderStyle;
04134 }
04135 
04136 void XFRecord::setLeftBorderStyle( unsigned style )
04137 {
04138   d->leftBorderStyle = style;
04139 }
04140 
04141 unsigned XFRecord::leftBorderColor() const
04142 {
04143   return d->leftBorderColor;
04144 }
04145 
04146 void XFRecord::setLeftBorderColor( unsigned color )
04147 {
04148   d->leftBorderColor = color;
04149 }
04150 
04151 unsigned XFRecord::rightBorderStyle() const
04152 {
04153   return d->rightBorderStyle;
04154 }
04155 
04156 void XFRecord::setRightBorderStyle( unsigned style )
04157 {
04158   d->rightBorderStyle = style;
04159 }
04160 
04161 unsigned XFRecord::rightBorderColor() const
04162 {
04163   return d->rightBorderColor;
04164 }
04165 
04166 void XFRecord::setRightBorderColor( unsigned color )
04167 {
04168   d->rightBorderColor = color;
04169 }
04170 
04171 unsigned XFRecord::topBorderStyle() const
04172 {
04173   return d->topBorderStyle;
04174 }
04175 
04176 void XFRecord::setTopBorderStyle( unsigned style )
04177 {
04178   d->topBorderStyle = style;
04179 }
04180 
04181 unsigned XFRecord::topBorderColor() const
04182 {
04183   return d->topBorderColor;
04184 }
04185 
04186 void XFRecord::setTopBorderColor( unsigned color )
04187 {
04188   d->topBorderColor = color;
04189 }
04190 
04191 unsigned XFRecord::bottomBorderStyle() const
04192 {
04193   return d->bottomBorderStyle;
04194 }
04195 
04196 void XFRecord::setBottomBorderStyle( unsigned style )
04197 {
04198   d->bottomBorderStyle = style;
04199 }
04200 
04201 unsigned XFRecord::bottomBorderColor() const
04202 {
04203   return d->bottomBorderColor;
04204 }
04205 
04206 void XFRecord::setBottomBorderColor( unsigned color )
04207 {
04208   d->bottomBorderColor = color;
04209 }
04210 
04211 bool XFRecord::diagonalTopLeft() const
04212 {
04213   return d->diagonalTopLeft;
04214 }
04215 
04216 void XFRecord::setDiagonalTopLeft( bool dd )
04217 {
04218   d->diagonalTopLeft = dd;
04219 }
04220 
04221 bool XFRecord::diagonalBottomLeft() const
04222 {
04223   return d->diagonalBottomLeft;
04224 }
04225 
04226 void XFRecord::setDiagonalBottomLeft( bool dd )
04227 {
04228   d->diagonalBottomLeft = dd;
04229 }
04230 
04231 unsigned XFRecord::diagonalStyle() const
04232 {
04233   return d->diagonalStyle;
04234 }
04235 
04236 void XFRecord::setDiagonalStyle( unsigned style )
04237 {
04238   d->diagonalStyle = style;
04239 }
04240 
04241 unsigned XFRecord::diagonalColor() const
04242 {
04243   return d->diagonalColor;
04244 }
04245 
04246 void XFRecord::setDiagonalColor( unsigned color )
04247 {
04248   d->diagonalColor = color;
04249 }
04250 
04251 unsigned XFRecord::fillPattern() const
04252 {
04253   return d->fillPattern;
04254 }
04255 
04256 void XFRecord::setFillPattern( unsigned pattern ) 
04257 {
04258   d->fillPattern = pattern;
04259 }
04260 
04261 unsigned XFRecord::patternForeColor() const
04262 {
04263   return d->patternForeColor;
04264 }
04265 
04266 void XFRecord::setPatternForeColor( unsigned color )
04267 {
04268   d->patternForeColor = color;
04269 }
04270 
04271 unsigned XFRecord::patternBackColor() const
04272 {
04273   return d->patternBackColor;
04274 }
04275 
04276 void XFRecord::setPatternBackColor( unsigned color )
04277 {
04278   d->patternBackColor = color;
04279 }
04280 
04281 void XFRecord::setData( unsigned size, const unsigned char* data )
04282 {
04283   unsigned recordSize = ( version() == Excel97 ) ? 20: 16;
04284   if( size < recordSize ) return;
04285   
04286   setFontIndex( readU16( data ) ); 
04287   setFormatIndex( readU16( data+2 ) );
04288   
04289   unsigned protection = readU16( data+4 ) & 7;
04290   setLocked( protection & 1 );
04291   setFormulaHidden( protection & 2 );
04292   
04293   setParentStyle( readU16( data+4 ) >> 4 );
04294   
04295   unsigned align = data[6];
04296   setHorizontalAlignment( align & 0x07 );
04297   setVerticalAlignment( align >> 4 );
04298   setTextWrap( align & 0x08 );
04299   
04300   unsigned angle = data[7];
04301   setRotationAngle( ( angle != 255 ) ? ( angle & 0x7f ) : 0 );
04302   setStackedLetters( angle == 255 );
04303   
04304   if( version() == Excel97 )
04305   { 
04306     unsigned options = data[8];
04307     unsigned attributes = data[9];
04308 
04309     setIndentLevel( options & 0x0f );
04310     setShrinkContent( options & 0x10 );
04311   
04312     unsigned linestyle = readU16( data + 10 );
04313     unsigned color1 = readU16( data + 12 );
04314     // unsigned color2 = readU16( data + 14 );
04315     unsigned flag = readU16( data + 16 );
04316     unsigned fill = readU16( data + 18 );
04317   
04318     setLeftBorderStyle( linestyle & 0xf );
04319     setRightBorderStyle( ( linestyle >> 4 ) & 0xf );
04320     setTopBorderStyle( ( linestyle >> 8 ) & 0xf );
04321     setBottomBorderStyle( ( linestyle >> 12 ) & 0xf );
04322   
04323     setLeftBorderColor( color1 & 0x7f );
04324     setRightBorderColor( ( color1 >> 7 ) & 0x7f );
04325     setTopBorderColor( color1 & 0x7f );
04326     setBottomBorderColor( ( color1 >> 7 ) & 0x7f );
04327   
04328     setDiagonalTopLeft( color1 & 0x40 );
04329     setDiagonalBottomLeft( color1 & 0x40 );
04330     setDiagonalStyle( ( flag >> 4 ) & 0x1e  );
04331     setDiagonalColor( ( ( flag & 0x1f ) << 2 ) + (  ( color1 >> 14 ) & 3 ));
04332     
04333     setFillPattern( ( flag >> 10 ) & 0x3f );
04334     setPatternForeColor( fill & 0x7f );
04335     setPatternBackColor( ( fill >> 7 ) & 0x7f );
04336   }
04337   else
04338   {
04339     unsigned data1 = readU32( data + 8 );
04340     unsigned data2 = readU32( data + 12 );
04341     
04342     setPatternForeColor( data1 & 0x7f );
04343     setPatternBackColor( ( data1 >> 7 ) & 0x7f );
04344     setFillPattern( ( data1 >> 16 ) & 0x3f );
04345     
04346     setBottomBorderStyle( ( data1 >> 22 ) & 0x07 );
04347     setBottomBorderColor( ( data1 >> 25 ) & 0x7f ); 
04348     
04349     setTopBorderStyle( data2 & 0x07 );
04350     setLeftBorderStyle( ( data2 >> 3 ) & 0x07 );
04351     setRightBorderStyle( ( data2 >> 6 ) & 0x07 );
04352     
04353     setTopBorderColor( ( data2 >> 9 ) & 0x7f );
04354     setLeftBorderColor( ( data2 >> 16 ) & 0x7f );
04355     setRightBorderColor( ( data2 >> 23 ) & 0x7f );
04356   }
04357 }
04358 
04359 void XFRecord::dump( std::ostream& out ) const
04360 {
04361   out << "XF" << std::endl;
04362   out << "       Parent Style : " << parentStyle() << std::endl;
04363   out << "         Font Index : " << fontIndex() << std::endl;
04364   out << "       Format Index : " << formatIndex() << std::endl;
04365   out << "             Locked : " << (locked()?"Yes":"No") << std::endl;
04366   out << " Formula Visibility : " << (formulaHidden()?"Hidden":"Visible") << std::endl;
04367   out << "   Horizontal Align : " << horizontalAlignmentAsString() << std::endl;
04368   out << "     Vertical Align : " << verticalAlignmentAsString() << std::endl;
04369   out << "          Text Wrap : " << ( textWrap() ? "yes" : "no" ) << std::endl;
04370   out << "          Rotation  : " << rotationAngle() << std::endl;
04371   out << "    Stacked Letters : " << ( stackedLetters() ? "yes" : "no" ) << std::endl;
04372   out << "       Indent Level : " << indentLevel() << std::endl;
04373   out << "      Shrink To Fit : " << ( shrinkContent() ? "yes" : "no" ) << std::endl;
04374   out << "        Left Border : Style " << leftBorderStyle();
04375   out << " Color: " << leftBorderColor() << std::endl;
04376   out << "       Right Border : Style " << rightBorderStyle();
04377   out << " Color: " << rightBorderColor() << std::endl;
04378   out << "         Top Border : Style " << topBorderStyle();
04379   out << " Color: " << topBorderColor() << std::endl;
04380   out << "      Bottom Border : Style " << bottomBorderStyle();
04381   out << " Color: " << bottomBorderColor() << std::endl;
04382   out << "     Diagonal Lines : " ;
04383   if ( diagonalTopLeft() ) out << "TopLeft ";
04384   if ( diagonalBottomLeft() ) out << "BottomLeft ";
04385   out << "Style " << diagonalStyle() << " Color: " << diagonalColor() << std::endl;
04386   out << "       Fill Pattern : " << fillPattern() << std::endl;
04387   out << "         Fill Color : Fore " << patternForeColor() << " Back: " 
04388   << patternBackColor() << std::endl;
04389 }
04390 
04391 //=============================================
04392 //          ExcelReader
04393 //=============================================
04394 
04395 class ExcelReader::Private
04396 {
04397 public:
04398 
04399   // the workbook
04400   Workbook* workbook;
04401   
04402   // password protection flag
04403   // TODO: password hash for record decryption
04404   bool passwordProtected;
04405 
04406   // active sheet, all cell records will be stored here
04407   Sheet* activeSheet;
04408   
04409   // for FORMULA+STRING record pair
04410   Cell* formulaCell;
04411   
04412   // mapping from BOF pos to actual Sheet
04413   std::map<unsigned,Sheet*> bofMap;
04414   
04415   // shared-string table
04416   std::vector<UString> stringTable;
04417   
04418   // table of format
04419   std::map<unsigned,FormatRecord> formatTable;
04420   std::map<unsigned,UString> formatsTable;
04421   
04422   // table of font
04423   std::vector<FontRecord> fontTable;
04424   
04425   // table of Xformat
04426   std::vector<XFRecord> xfTable;
04427   
04428   // color table (from Palette record)
04429   std::vector<Color> colorTable;
04430   
04431   // mapping from font index to Swinder::FormatFont
04432   std::map<unsigned,FormatFont> fontCache;
04433 
04434   // for NAME and EXTERNNAME
04435   std::vector<UString> nameTable;
04436 };
04437 
04438 ExcelReader::ExcelReader()
04439 {
04440   d = new ExcelReader::Private();
04441   
04442   d->workbook    = 0;
04443   d->activeSheet = 0;
04444   d->formulaCell = 0;
04445   
04446   d->passwordProtected = false;
04447   
04448   // initialize palette
04449   static const char *const default_palette[64-8] =  // default palette for all but the first 8 colors
04450   {
04451       "#000000", "#ffffff", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff",
04452       "#00ffff", "#800000", "#008000", "#000080", "#808000", "#800080", "#008080",
04453       "#c0c0c0", "#808080", "#9999ff", "#993366", "#ffffcc", "#ccffff", "#660066",
04454       "#ff8080", "#0066cc", "#ccccff", "#000080", "#ff00ff", "#ffff00", "#00ffff",
04455       "#800080", "#800000", "#008080", "#0000ff", "#00ccff", "#ccffff", "#ccffcc",
04456       "#ffff99", "#99ccff", "#ff99cc", "#cc99ff", "#ffcc99", "#3366ff", "#33cccc",
04457       "#99cc00", "#ffcc00", "#ff9900", "#ff6600", "#666699", "#969696", "#003366",
04458       "#339966", "#003300", "#333300", "#993300", "#993366", "#333399", "#333333",
04459   };
04460   for( int i = 0; i < 64-8; i++ ) {
04461     d->colorTable.push_back(Color(default_palette[i]));
04462   }
04463 }
04464 
04465 ExcelReader::~ExcelReader()
04466 {
04467   delete d;
04468 }
04469 
04470 bool ExcelReader::load( Workbook* workbook, const char* filename )
04471 {
04472   POLE::Storage storage( filename );
04473   if( !storage.open() )
04474   {
04475     std::cerr << "Cannot open " << filename << std::endl;
04476     return false;
04477   }
04478   
04479   unsigned version = Swinder::Excel97;
04480   POLE::Stream* stream;
04481   stream = new POLE::Stream( &storage, "/Workbook" );
04482   if( stream->fail() )
04483   {
04484     delete stream;
04485     stream = new POLE::Stream( &storage, "/Book" );
04486     version = Swinder::Excel95;
04487   }
04488   
04489   if( stream->fail() )
04490   {
04491     std::cerr << filename << " is not Excel workbook" << std::endl;
04492     delete stream;
04493     return false;
04494   }
04495   
04496   unsigned long stream_size = stream->size();
04497 
04498   unsigned int buffer_size = 65536;     // current size of the buffer
04499   unsigned char *buffer = (unsigned char *) malloc(buffer_size);
04500   unsigned char small_buffer[128];  // small, fixed size buffer
04501 
04502   workbook->clear();  
04503   d->workbook = workbook;
04504   
04505   d->passwordProtected = false;
04506   
04507   // assume
04508 
04509   while( stream->tell() < stream_size )
04510   {
04511   
04512     // this is set by FILEPASS record
04513     // subsequent records will need to be decrypted
04514     // since we do not support it yet, we have to bail out
04515     if(d->passwordProtected)
04516     {
04517       d->workbook->setPasswordProtected( true );
04518       break;
04519     }
04520   
04521     // get record type and data size
04522     unsigned long pos = stream->tell();
04523     unsigned bytes_read = stream->read( buffer, 4 );
04524     if( bytes_read != 4 ) break;
04525     
04526     unsigned long type = readU16( buffer );
04527     unsigned long size = readU16( buffer + 2 );
04528     
04529     // verify buffer is large enough to hold the record data
04530     if (size > buffer_size) {
04531         buffer = (unsigned char *) realloc(buffer, size);
04532     buffer_size = size;
04533     }
04534     
04535     // load actual record data
04536     bytes_read = stream->read( buffer, size );
04537     if( bytes_read != size ) break;
04538 
04539     // save current position in stream, to be able to restore the position later on
04540     unsigned long saved_pos;
04541     // repeatedly check if the next record is type 0x3C, a continuation record
04542     unsigned long next_type; // the type of the next record
04543     do {
04544         saved_pos = stream->tell();
04545 
04546         bytes_read = stream->read( small_buffer, 4 );
04547     if (bytes_read != 4) break;
04548     
04549     next_type = readU16( small_buffer );
04550     unsigned long next_size = readU16( small_buffer + 2 );
04551     
04552     if (next_type == 0x3C) {
04553         // type of next record is 0x3C, so go ahead and append the contents of the next record to the buffer
04554 
04555         // first verify the buffer is large enough to hold all the data
04556         if ( (size + next_size) > buffer_size) {
04557                 buffer = (unsigned char *) realloc(buffer, size + next_size);
04558         buffer_size = size + next_size;
04559         }
04560 
04561         // next read the data of the record
04562         bytes_read = stream->read( buffer + size, next_size );
04563         if (bytes_read != next_size) {
04564             std::cout << "ERROR!" << std::endl;
04565         break;
04566         }
04567 
04568         // if the first read byte is a zero, remove it (at least that is what the old excel97 filter did...)
04569         if (buffer[size] == 0) {
04570                 memmove( buffer + size, buffer + size + 1, --next_size );
04571         }
04572 
04573         // and finally update size
04574         size += next_size;
04575     }
04576     } while (next_type == 0x3C);
04577 
04578     // restore position in stream to the beginning of the next record
04579     stream->seek( saved_pos );
04580     
04581     // skip record type 0, this is just for filler
04582     if( type == 0 ) continue;
04583     
04584     // create the record using the factory
04585     Record* record = Record::create( type );
04586 
04587     if( record )
04588     {
04589       // setup the record and invoke handler
04590       record->setVersion( version );
04591       record->setData( size, buffer );
04592       record->setPosition( pos );
04593       
04594       handleRecord( record );
04595       
04596       // special handling to find Excel version
04597       if ( record->rtti() == BOFRecord::id )
04598       {
04599         BOFRecord* bof = static_cast<BOFRecord*>(record);
04600         if( bof ) if( bof->type() == BOFRecord::Workbook )
04601         version = bof->version();
04602       }
04603 
04604 #ifdef SWINDER_XLS2RAW
04605       std::cout << "Record 0x";
04606       std::cout << std::setfill('0') << std::setw(4) << std::hex << record->rtti();
04607       std::cout << " ";
04608       std::cout << std::dec;
04609       record->dump( std::cout );
04610       std::cout << std::endl;
04611 #endif
04612 
04613       delete record;
04614     }
04615     
04616 #ifdef SWINDER_XLS2RAW
04617     if( !record )
04618     {
04619       std::cout << "Record 0x";
04620       std::cout << std::setfill('0') << std::setw(4) << std::hex << type;
04621       std::cout << std::dec;
04622       std::cout << std::endl;
04623       std::cout << std::endl;
04624     }
04625 #endif
04626 
04627   }
04628 
04629   free(buffer);
04630   
04631   delete stream;
04632   
04633   storage.close();
04634   
04635   return true;
04636 }
04637 
04638 void ExcelReader::handleRecord( Record* record )
04639 {
04640   if( !record ) return;
04641   
04642   unsigned type = record->rtti();
04643   switch( type )
04644   {
04645     case BottomMarginRecord::id: 
04646       handleBottomMargin( static_cast<BottomMarginRecord*>( record ) ); break;
04647     case BoundSheetRecord::id: 
04648       handleBoundSheet( static_cast<BoundSheetRecord*>( record ) ); break;
04649     case BOFRecord::id: 
04650       handleBOF( static_cast<BOFRecord*>( record ) ); break;
04651     case BoolErrRecord::id: 
04652       handleBoolErr( static_cast<BoolErrRecord*>( record ) ); break;
04653     case BlankRecord::id: 
04654       handleBlank( static_cast<BlankRecord*>( record ) ); break;
04655     case CalcModeRecord::id: 
04656       handleCalcMode( static_cast<CalcModeRecord*>( record ) ); break;
04657     case ColInfoRecord::id: 
04658       handleColInfo( static_cast<ColInfoRecord*>( record ) ); break;
04659     case ExternNameRecord::id: 
04660       handleExternName( static_cast<ExternNameRecord*>( record ) ); break;
04661     case FilepassRecord::id: 
04662       handleFilepass( static_cast<FilepassRecord*>( record ) ); break;
04663     case FormatRecord::id: 
04664       handleFormat( static_cast<FormatRecord*>( record ) ); break;
04665     case FormulaRecord::id: 
04666       handleFormula( static_cast<FormulaRecord*>( record ) ); break;
04667     case FontRecord::id: 
04668       handleFont( static_cast<FontRecord*>( record ) ); break;
04669     case FooterRecord::id: 
04670       handleFooter( static_cast<FooterRecord*>( record ) ); break;
04671     case HeaderRecord::id: 
04672       handleHeader( static_cast<HeaderRecord*>( record ) ); break;
04673     case LabelRecord::id: 
04674       handleLabel( static_cast<LabelRecord*>( record ) ); break;
04675     case LabelSSTRecord::id: 
04676       handleLabelSST( static_cast<LabelSSTRecord*>( record ) ); break;
04677     case LeftMarginRecord::id: 
04678       handleLeftMargin( static_cast<LeftMarginRecord*>( record ) ); break;
04679     case MergedCellsRecord::id: 
04680       handleMergedCells( static_cast<MergedCellsRecord*>( record ) ); break;
04681     case MulBlankRecord::id: 
04682       handleMulBlank( static_cast<MulBlankRecord*>( record ) ); break;
04683     case MulRKRecord::id: 
04684       handleMulRK( static_cast<MulRKRecord*>( record ) ); break;
04685     case NameRecord::id: 
04686       handleName( static_cast<NameRecord*>( record ) ); break;
04687     case NumberRecord::id: 
04688       handleNumber( static_cast<NumberRecord*>( record ) ); break;
04689     case PaletteRecord::id: 
04690       handlePalette( static_cast<PaletteRecord*>( record ) ); break;
04691     case RightMarginRecord::id: 
04692       handleRightMargin( static_cast<RightMarginRecord*>( record ) ); break;
04693     case RKRecord::id: 
04694       handleRK( static_cast<RKRecord*>( record ) ); break;
04695     case RowRecord::id: 
04696       handleRow( static_cast<RowRecord*>( record ) ); break;
04697     case RStringRecord::id: 
04698       handleRString( static_cast<RStringRecord*>( record ) ); break;
04699     case SSTRecord::id: 
04700       handleSST( static_cast<SSTRecord*>( record ) ); break;
04701     case StringRecord::id: 
04702       handleString( static_cast<StringRecord*>( record ) ); break;
04703     case TopMarginRecord::id: 
04704       handleTopMargin( static_cast<TopMarginRecord*>( record ) ); break;
04705     case XFRecord::id: 
04706       handleXF( static_cast<XFRecord*>( record ) ); break;
04707     default:
04708       break;  
04709   }
04710 }
04711 
04712 void ExcelReader::handleBottomMargin( BottomMarginRecord* record )
04713 {
04714   if( !record ) return;
04715 
04716   if( !d->activeSheet ) return;
04717 
04718   // convert from inches to points
04719   double margin = record->bottomMargin() * 72.0;
04720   d->activeSheet->setBottomMargin( margin );
04721 }
04722 
04723 // FIXME does the order of sheet follow BOUNDSHEET of BOF(Worksheet) ?
04724 // for now, assume BOUNDSHEET, hence we should create the sheet here
04725 void ExcelReader::handleBoundSheet( BoundSheetRecord* record )
04726 {
04727   if( !record ) return;
04728   
04729   // only care for Worksheet, forget everything else
04730   if( record->type() == BoundSheetRecord::Worksheet )
04731   {
04732     // create a new sheet
04733     Sheet* sheet = new Sheet( d->workbook );
04734     sheet->setName( record->sheetName() );
04735     sheet->setVisible( record->visible() );
04736 
04737     d->workbook->appendSheet( sheet );
04738 
04739     // update bof position map
04740     unsigned bofPos = record->bofPosition();
04741     d->bofMap[ bofPos ] = sheet;
04742   }
04743 }
04744 
04745 void ExcelReader::handleBOF( BOFRecord* record )
04746 {
04747   if( !record ) return;
04748   
04749   if( record->type() == BOFRecord::Worksheet )
04750   {
04751     // find the sheet and make it active
04752     // which sheet ? look from from previous BoundSheet
04753     Sheet* sheet = d->bofMap[ record->position() ];
04754     if( sheet ) d->activeSheet = sheet;
04755   }
04756 }
04757 
04758 void ExcelReader::handleBoolErr( BoolErrRecord* record )
04759 {
04760   if( !record ) return;
04761   
04762   if( !d->activeSheet ) return;
04763   
04764   unsigned column = record->column();
04765   unsigned row = record->row();
04766   unsigned xfIndex = record->xfIndex();
04767   
04768   Cell* cell = d->activeSheet->cell( column, row, true );
04769   if( cell )
04770   {
04771     cell->setValue( record->value() );
04772     cell->setFormat( convertFormat( xfIndex ) );
04773   }
04774 }
04775 
04776 void ExcelReader::handleBlank( BlankRecord* record )
04777 {
04778   if( !record ) return;
04779   
04780   if( !d->activeSheet ) return;
04781   
04782   unsigned column = record->column();
04783   unsigned row = record->row();
04784   unsigned xfIndex = record->xfIndex();
04785   
04786   Cell* cell = d->activeSheet->cell( column, row, true ); 
04787   if( cell )
04788   {
04789     cell->setFormat( convertFormat( xfIndex ) );
04790   }
04791 }
04792 
04793 void ExcelReader::handleCalcMode( CalcModeRecord* record )
04794 {
04795   if( !record ) return;
04796   
04797   d->workbook->setAutoCalc( record->autoCalc() );
04798 }
04799   
04800 void ExcelReader::handleColInfo( ColInfoRecord* record )
04801 {
04802   if( !record ) return;
04803   
04804   if( !d->activeSheet ) return;
04805   
04806   unsigned firstColumn = record->firstColumn();
04807   unsigned lastColumn = record->lastColumn();
04808   unsigned xfIndex = record->xfIndex();
04809   unsigned width = record->width();
04810   bool hidden = record->hidden();
04811   
04812   for( unsigned i = firstColumn; i <= lastColumn; i++ )
04813   {
04814     Column* column = d->activeSheet->column( i, true );
04815     if( column )
04816     {
04817       column->setWidth( width / 120 );
04818       column->setFormat( convertFormat( xfIndex ) );
04819       column->setVisible( !hidden );
04820     }
04821   }  
04822 }
04823 
04824 void ExcelReader::handleDateMode( DateModeRecord* record )
04825 {
04826   if( !record ) return;
04827   
04828   // FIXME FIXME what to do ??
04829   std::cerr << "WARNING: Workbook uses unsupported 1904 Date System " << std::endl;
04830 }
04831 
04832 void ExcelReader::handleDimension( DimensionRecord* record )
04833 {
04834   if( !record ) return;
04835   
04836   // in the mean time we don't need to handle this because we don't care
04837   // about the used range of the sheet  
04838 }
04839 
04840 void ExcelReader::handleLabel( LabelRecord* record )
04841 {
04842   if( !record ) return;
04843 
04844   if( !d->activeSheet ) return;
04845 
04846   unsigned column = record->column();
04847   unsigned row = record->row();  
04848   unsigned xfIndex = record->xfIndex();
04849   UString label = record->label();
04850   
04851   Cell* cell = d->activeSheet->cell( column, row, true );
04852   if( cell )
04853   {
04854     cell->setValue( Value( label ) );
04855     cell->setFormat( convertFormat( xfIndex ) );
04856   }
04857 }
04858 
04859 void ExcelReader::handleLeftMargin( LeftMarginRecord* record )
04860 {
04861   if( !record ) return;
04862 
04863   if( !d->activeSheet ) return;
04864 
04865   // convert from inches to points
04866   double margin = record->leftMargin() * 72.0;
04867   d->activeSheet->setLeftMargin( margin );
04868 }
04869 
04870 void ExcelReader::handleFormat( FormatRecord* record )
04871 {
04872   if( !record ) return;
04873 
04874   d->formatTable[ record->index() ] = *record;
04875   d->formatsTable[ record->index() ] = record->formatString();
04876 }
04877 
04878 void ExcelReader::handleFormula( FormulaRecord* record )
04879 {
04880   if( !record ) return;
04881 
04882   if( !d->activeSheet ) return;
04883   
04884   unsigned column = record->column();
04885   unsigned row = record->row();  
04886   unsigned xfIndex = record->xfIndex();
04887   Value value = record->result();
04888   
04889   UString formula = decodeFormula( row, column, record->tokens() );
04890   
04891   Cell* cell = d->activeSheet->cell( column, row, true );
04892   if( cell )
04893   {
04894     cell->setValue( value );
04895     if( !formula.isEmpty() )
04896       cell->setFormula( formula );
04897     cell->setFormat( convertFormat( xfIndex ) );
04898     
04899     // if value is string, real value is in subsequent String record
04900     if( value.isString() )
04901       d->formulaCell = cell;
04902   }
04903 }
04904 
04905 void ExcelReader::handleExternName( ExternNameRecord* record )
04906 {
04907   if( !record ) return;
04908 
04909   d->nameTable.push_back( record->externName() );
04910 }
04911 
04912 void ExcelReader::handleFilepass( FilepassRecord* record )
04913 {
04914   if( !record ) return;
04915   
04916   d->passwordProtected = true;
04917 }
04918 
04919 void ExcelReader::handleFont( FontRecord* record )
04920 {
04921   if( !record ) return;
04922 
04923   d->fontTable.push_back( *record );
04924 
04925   // font #4 is never used, so add a dummy one
04926   if( d->fontTable.size() == 4 )
04927     d->fontTable.push_back( FontRecord() );
04928 }
04929 
04930 void ExcelReader::handleFooter( FooterRecord* record )
04931 {
04932   if( !record ) return;
04933 
04934   if( !d->activeSheet ) return;
04935 
04936   UString footer = record->footer();
04937   UString left, center, right;
04938   int pos = -1, len = 0;
04939 
04940   // left part
04941   pos = footer.find( UString("&L") );
04942   if( pos >= 0 )
04943   {
04944     pos += 2;
04945     len = footer.find( UString("&C") ) - pos;
04946     if( len > 0 )
04947     {
04948       left = footer.substr( pos, len );
04949       footer = footer.substr( pos+len, footer.length() );
04950     }
04951   }
04952 
04953   // center part
04954   pos = footer.find( UString("&C") );
04955   if( pos >= 0 )
04956   {
04957     pos += 2;
04958     len = footer.find( UString("&R") ) - pos;
04959     if( len > 0 )
04960     {
04961       center = footer.substr( pos, len );
04962       footer = footer.substr( pos+len, footer.length() );
04963     }
04964   }
04965 
04966   // right part
04967   pos = footer.find( UString("&R") );
04968   if( pos >= 0 )
04969   {
04970     pos += 2;
04971     right = footer.substr( pos, footer.length() - pos );
04972   }
04973 
04974   d->activeSheet->setLeftFooter( left );
04975   d->activeSheet->setCenterFooter( center );
04976   d->activeSheet->setRightFooter( right );
04977 }
04978 
04979 void ExcelReader::handleHeader( HeaderRecord* record )
04980 {
04981   if( !record ) return;
04982 
04983   if( !d->activeSheet ) return;
04984 
04985   UString header = record->header();
04986   UString left, center, right;
04987   int pos = -1, len = 0;
04988 
04989   // left part of the header
04990   pos = header.find( UString("&L") );
04991   if( pos >= 0 )
04992   {
04993     pos += 2;
04994     len = header.find( UString("&C") ) - pos;
04995     if( len > 0 )
04996     {
04997       left = header.substr( pos, len );
04998       header = header.substr( pos+len, header.length() );
04999     }
05000   }
05001 
05002   // center part of the header
05003   pos = header.find( UString("&C") );
05004   if( pos >= 0 )
05005   {
05006     pos += 2;
05007     len = header.find( UString("&R") ) - pos;
05008     if( len > 0 )
05009     {
05010       center = header.substr( pos, len );
05011       header = header.substr( pos+len, header.length() );
05012     }
05013   }
05014 
05015   // right part of the header
05016   pos = header.find( UString("&R") );
05017   if( pos >= 0 )
05018   {
05019     pos += 2;
05020     right = header.substr( pos, header.length() - pos );
05021   }
05022 
05023   d->activeSheet->setLeftHeader( left );
05024   d->activeSheet->setCenterHeader( center );
05025   d->activeSheet->setRightHeader( right );
05026 }
05027 
05028 void ExcelReader::handleLabelSST( LabelSSTRecord* record )
05029 {
05030   if( !record ) return;
05031 
05032   if( !d->activeSheet ) return;
05033 
05034   unsigned column = record->column();
05035   unsigned row = record->row();
05036   unsigned index = record->sstIndex();
05037   unsigned xfIndex = record->xfIndex();
05038 
05039   UString str;
05040   if( index < d->stringTable.size() )
05041     str = d->stringTable[ index ];
05042 
05043   Cell* cell = d->activeSheet->cell( column, row, true );
05044   if( cell )
05045   {
05046     cell->setValue( Value( str ) );
05047     cell->setFormat( convertFormat( xfIndex) );
05048   }
05049 }
05050 
05051 void ExcelReader::handleMergedCells( MergedCellsRecord* record )
05052 {
05053   if( !record ) return;
05054   
05055   if( !d->activeSheet ) return;
05056   
05057   for( unsigned i = 0; i < record->count(); i++ )
05058   {
05059     unsigned firstRow = record->firstRow( i );
05060     unsigned lastRow = record->lastRow( i );
05061     unsigned firstColumn = record->firstColumn( i );
05062     unsigned lastColumn = record->lastColumn( i );
05063     
05064     Cell* cell = d->activeSheet->cell( firstColumn, firstRow, true );
05065     if( cell )
05066     {
05067       cell->setColumnSpan( lastColumn - firstColumn + 1 );
05068       cell->setRowSpan( lastRow - firstRow + 1 );
05069     }
05070   }
05071 }
05072 
05073 void ExcelReader::handleMulBlank( MulBlankRecord* record )
05074 {
05075   if( !record ) return;
05076 
05077   if( !d->activeSheet ) return;
05078   
05079   unsigned firstColumn = record->firstColumn();
05080   unsigned lastColumn = record->lastColumn();
05081   unsigned row = record->row();
05082   
05083   for( unsigned column = firstColumn; column <= lastColumn; column++ )
05084   {
05085     Cell* cell = d->activeSheet->cell( column, row, true );
05086     if( cell )
05087     {
05088       cell->setFormat( convertFormat( record->xfIndex( column - firstColumn ) ) );
05089     }
05090   }
05091 }
05092 
05093 void ExcelReader::handleMulRK( MulRKRecord* record )
05094 {
05095   if( !record ) return;
05096   
05097   if( !d->activeSheet ) return;
05098   
05099   unsigned firstColumn = record->firstColumn();
05100   unsigned lastColumn = record->lastColumn();
05101   unsigned row = record->row();
05102   
05103   for( unsigned column = firstColumn; column <= lastColumn; column++ )
05104   {
05105     Cell* cell = d->activeSheet->cell( column, row, true );    
05106     if( cell )
05107     {
05108       unsigned i = column - firstColumn;
05109       Value value;
05110       if( record->isInteger( i ) )
05111         value.setValue( record->asInteger( i ) );
05112       else
05113         value.setValue( record->asFloat( i ) );
05114       cell->setValue( value );
05115       cell->setFormat( convertFormat( record->xfIndex( column-firstColumn ) ) );
05116     }
05117   }
05118 }
05119 
05120 void ExcelReader::handleName( NameRecord* record )
05121 {
05122   if( !record ) return;
05123 
05124   d->nameTable.push_back( record->definedName() );
05125 }
05126 
05127 void ExcelReader::handleNumber( NumberRecord* record )
05128 {
05129   if( !record ) return;
05130   
05131   if( !d->activeSheet ) return;
05132   
05133   unsigned column = record->column();
05134   unsigned row = record->row();
05135   unsigned xfIndex = record->xfIndex();
05136   double number = record->number();
05137   
05138   Cell* cell = d->activeSheet->cell( column, row, true );
05139   if( cell )
05140   {
05141     cell->setValue( Value( number ) );
05142     cell->setFormat( convertFormat( xfIndex) );
05143   }
05144 }
05145 
05146 void ExcelReader::handlePalette( PaletteRecord* record )
05147 {
05148   if( !record ) return;
05149   
05150   d->colorTable.clear();
05151   for( unsigned i = 0; i < record->count(); i++ )
05152     d->colorTable.push_back( record->color( i ) );
05153 }
05154   
05155 void ExcelReader::handleRightMargin( RightMarginRecord* record )
05156 {
05157   if( !record ) return;
05158   
05159   if( !d->activeSheet ) return;
05160   
05161   // convert from inches to points
05162   double margin = record->rightMargin() * 72.0;
05163   d->activeSheet->setRightMargin( margin );  
05164 }
05165 
05166 void ExcelReader::handleRK( RKRecord* record )
05167 {
05168   if( !record ) return;
05169   
05170   if( !d->activeSheet ) return;
05171   
05172   unsigned column = record->column();
05173   unsigned row = record->row();
05174   unsigned xfIndex = record->xfIndex();
05175   
05176   Value value;
05177   if( record->isInteger() )
05178     value.setValue( record->asInteger() );
05179   else
05180     value.setValue( record->asFloat() );
05181   
05182   Cell* cell = d->activeSheet->cell( column, row, true );
05183   if( cell )
05184   {
05185     cell->setValue( value );
05186     cell->setFormat( convertFormat( xfIndex) );
05187   }
05188 }
05189 
05190 void ExcelReader::handleRow( RowRecord* record )
05191 {
05192   if( !record ) return;
05193   
05194   if( !d->activeSheet ) return;
05195 
05196   unsigned index = record->row();  
05197   unsigned xfIndex = record->xfIndex();
05198   unsigned height = record->height();
05199   bool hidden = record->hidden();
05200   
05201   Row* row = d->activeSheet->row( index, true );
05202   if( row )
05203   {
05204     row->setHeight( height / 20.0 );
05205     row->setFormat( convertFormat( xfIndex ) );
05206     row->setVisible( !hidden );
05207   }  
05208 }
05209 
05210 void ExcelReader::handleRString( RStringRecord* record )
05211 {
05212   if( !record ) return;
05213   
05214   if( !d->activeSheet ) return;
05215   
05216   unsigned column = record->column();
05217   unsigned row = record->row();  
05218   unsigned xfIndex = record->xfIndex();
05219   UString label = record->label();
05220   
05221   Cell* cell = d->activeSheet->cell( column, row, true );
05222   if( cell )
05223   {
05224     cell->setValue( Value( label ) );
05225     cell->setFormat( convertFormat( xfIndex) );
05226   }
05227 }
05228 
05229 void ExcelReader::handleSST( SSTRecord* record )
05230 {
05231   if( !record ) return;
05232   
05233   d->stringTable.clear();
05234   for( unsigned i = 0; i < record->count();i++ )
05235   {
05236     UString str = record->stringAt( i );
05237     d->stringTable.push_back( str );
05238   }
05239 }
05240 
05241 void ExcelReader::handleString( StringRecord* record )
05242 {
05243   if( !record ) return;
05244   
05245   if( !d->activeSheet ) return;
05246   if( !d->formulaCell ) return;
05247   
05248   d->formulaCell->setValue( record->value() );
05249   
05250   d->formulaCell = 0;
05251 }
05252 
05253 void ExcelReader::handleTopMargin( TopMarginRecord* record )
05254 {
05255   if( !record ) return;
05256 
05257   if( !d->activeSheet ) return;
05258 
05259 
05260   // convert from inches to points
05261   double margin = record->topMargin() * 72.0;
05262   d->activeSheet->setTopMargin( margin );
05263 }
05264 
05265 FormatFont ExcelReader::convertFont( unsigned fontIndex )
05266 {  
05267   // speed-up trick: check in the cache first  
05268   FormatFont font = d->fontCache[ fontIndex ];
05269   if( font.isNull() && ( fontIndex < d->fontTable.size() ))
05270   {
05271     FontRecord fr = d->fontTable[ fontIndex ];
05272     font.setFontSize( fr.height() / 20.0 );
05273     font.setFontFamily( fr.fontName() );
05274     font.setColor( convertColor( fr.colorIndex() ) );
05275     font.setBold( fr.boldness() > 500 );
05276     font.setItalic( fr.italic() );
05277     font.setStrikeout( fr.strikeout() );    
05278     font.setSubscript( fr.escapement() == FontRecord::Subscript );
05279     font.setSuperscript( fr.escapement() == FontRecord::Superscript );
05280     font.setUnderline( fr.underline() != FontRecord::None );
05281     
05282     // put in the cache for further use
05283     d->fontCache[ fontIndex ] = font;    
05284   }  
05285   
05286   return font;
05287 }
05288 
05289 Color ExcelReader::convertColor( unsigned colorIndex )
05290 {  
05291   if( ( colorIndex >= 8 ) && ( colorIndex < 0x40 ) )
05292     if( colorIndex-8 < d->colorTable.size() )
05293       return d->colorTable[ colorIndex-8 ];
05294   
05295   // FIXME the following colors depend on system color settings
05296   // 0x0040  system window text colour for border lines    
05297   // 0x0041  system window background colour for pattern background
05298   // 0x7fff  system window text colour for fonts
05299   if( colorIndex == 0x40 ) return Color( 0, 0, 0 );
05300   if( colorIndex == 0x41 ) return Color( 255, 255, 255 );
05301   if( colorIndex == 0x7fff ) return Color( 0, 0, 0 );
05302   
05303   // fallback: just "black"
05304   Color color;
05305 
05306   // standard colors: black, white, red, green, blue,
05307   // yellow, magenta, cyan
05308   switch( colorIndex )
05309   {
05310     case 0:   color = Color( 0, 0, 0 ); break; 
05311     case 1:   color = Color( 255, 255, 255 ); break; 
05312     case 2:   color = Color( 255, 0, 0 ); break;
05313     case 3:   color = Color( 0, 255, 0 ); break;
05314     case 4:   color = Color( 0, 0, 255 ); break;
05315     case 5:   color = Color( 255, 255, 0 ); break;
05316     case 6:   color = Color( 255, 0, 255 ); break;
05317     case 7:   color = Color( 0, 255, 255 ); break;
05318     default:  break;
05319   }
05320   
05321   return color;
05322 }
05323 
05324 // convert border style, e.g MediumDashed to a Pen
05325 static Pen convertBorderStyle( unsigned style )
05326 {
05327   Pen pen;
05328   switch( style )
05329   {
05330   case XFRecord::NoLine:
05331     pen.width = 0;
05332     pen.style = Pen::NoLine;
05333     break;
05334   case XFRecord::Thin:
05335     pen.width = 1;
05336     pen.style = Pen::SolidLine;
05337     break;
05338   case XFRecord::Medium:
05339     pen.width = 3;
05340     pen.style = Pen::SolidLine;
05341     break;
05342   case XFRecord::Dashed:
05343     pen.width = 1;
05344     pen.style = Pen::DashLine;
05345     break;
05346   case XFRecord::Dotted:
05347     pen.width = 1;
05348     pen.style = Pen::DotLine;
05349     break;
05350   case XFRecord::Thick:
05351     pen.width = 4;
05352     pen.style = Pen::SolidLine;
05353     break;
05354   case XFRecord::Double:
05355     // FIXME no equivalent ?
05356     pen.width = 4;
05357     pen.style = Pen::SolidLine;
05358     break;
05359   case XFRecord::Hair:
05360     // FIXME no equivalent ?
05361     pen.width = 1;
05362     pen.style = Pen::DotLine;
05363     break;
05364   case XFRecord::MediumDashed:
05365     pen.width = 3;
05366     pen.style = Pen::DashLine;
05367     break;
05368   case XFRecord::ThinDashDotted:
05369     pen.width = 1;
05370     pen.style = Pen::DashDotLine;
05371     break;
05372   case XFRecord::MediumDashDotted:
05373     pen.width = 3;
05374     pen.style = Pen::DashDotLine;
05375     break;
05376   case XFRecord::ThinDashDotDotted:
05377     pen.width = 1;
05378     pen.style = Pen::DashDotDotLine;
05379     break;
05380   case XFRecord::MediumDashDotDotted:
05381     pen.width = 3;
05382     pen.style = Pen::DashDotDotLine;
05383     break;
05384   case XFRecord::SlantedMediumDashDotted:
05385     // FIXME no equivalent ?
05386     pen.width = 3;
05387     pen.style = Pen::DashDotLine;
05388     break;
05389   default:
05390     // fallback, simple solid line
05391     pen.width = 1;
05392     pen.style = Pen::SolidLine;
05393     break;    
05394   };
05395   
05396   return pen;
05397 }
05398 
05399 unsigned convertPatternStyle( unsigned pattern )
05400 {
05401   switch ( pattern )
05402   {
05403     case 0x00: return FormatBackground::EmptyPattern;
05404     case 0x01: return FormatBackground::SolidPattern;
05405     case 0x02: return FormatBackground::Dense4Pattern;
05406     case 0x03: return FormatBackground::Dense3Pattern;
05407     case 0x04: return FormatBackground::Dense5Pattern;
05408     case 0x05: return FormatBackground::HorPattern;
05409     case 0x06: return FormatBackground::VerPattern;
05410     case 0x07: return FormatBackground::FDiagPattern;
05411     case 0x08: return FormatBackground::BDiagPattern;
05412     case 0x09: return FormatBackground::Dense1Pattern;
05413     case 0x0A: return FormatBackground::Dense2Pattern;
05414     case 0x0B: return FormatBackground::HorPattern;
05415     case 0x0C: return FormatBackground::VerPattern;
05416     case 0x0D: return FormatBackground::FDiagPattern;
05417     case 0x0E: return FormatBackground::BDiagPattern;
05418     case 0x0F: return FormatBackground::CrossPattern;
05419     case 0x10: return FormatBackground::DiagCrossPattern;
05420     case 0x11: return FormatBackground::Dense6Pattern;
05421     case 0x12: return FormatBackground::Dense7Pattern;
05422     default: return FormatBackground::SolidPattern; // fallback
05423   }
05424 }
05425 
05426 // big task: convert Excel XFormat into Swinder::Format
05427 Format ExcelReader::convertFormat( unsigned xfIndex )
05428 {
05429   Format format;
05430 
05431   if( xfIndex >= d->xfTable.size() ) return format;
05432 
05433   XFRecord xf = d->xfTable[ xfIndex ];
05434   
05435   UString valueFormat = d->formatsTable[xf.formatIndex()];
05436   if( valueFormat.isEmpty() )
05437     switch( xf.formatIndex() )
05438     {
05439       case  0:  valueFormat = "General"; break;
05440       case  1:  valueFormat = "0"; break;
05441       case  2:  valueFormat = "0.00"; break;
05442       case  3:  valueFormat = "#,##0"; break;
05443       case  4:  valueFormat = "#,##0.00"; break;
05444       case  5:  valueFormat = "\"$\"#,##0_);(\"S\"#,##0)"; break;
05445       case  6:  valueFormat = "\"$\"#,##0_);[Red](\"S\"#,##0)"; break;
05446       case  7:  valueFormat = "\"$\"#,##0.00_);(\"S\"#,##0.00)"; break;
05447       case  8:  valueFormat = "\"$\"#,##0.00_);[Red](\"S\"#,##0.00)"; break;
05448       case  9:  valueFormat = "0%"; break;
05449       case 10:  valueFormat = "0.00%"; break;
05450       case 11:  valueFormat = "0.00E+00"; break;
05451       case 12:  valueFormat = "#?/?"; break;
05452       case 13:  valueFormat = "#\?\?/\?\?"; break;
05453       case 14:  valueFormat = "M/D/YY"; break;
05454       case 15:  valueFormat = "D-MMM-YY"; break;
05455       case 16:  valueFormat = "D-MMM"; break;
05456       case 17:  valueFormat = "MMM-YY"; break;
05457       case 18:  valueFormat = "h:mm AM/PM"; break;
05458       case 19:  valueFormat = "h:mm:ss AM/PM"; break;
05459       case 20:  valueFormat = "h:mm"; break;
05460       case 21:  valueFormat = "h:mm:ss"; break;
05461       case 22:  valueFormat = "M/D/YY h:mm"; break;
05462       case 37:  valueFormat = "_(#,##0_);(#,##0)"; break;
05463       case 38:  valueFormat = "_(#,##0_);[Red](#,##0)"; break;
05464       case 39:  valueFormat = "_(#,##0.00_);(#,##0)"; break;
05465       case 40:  valueFormat = "_(#,##0.00_);[Red](#,##0)"; break;
05466       case 41:  valueFormat = "_(\"$\"*#,##0_);_(\"$\"*#,##0_);_(\"$\"*\"-\");(@_)"; break;
05467       case 42:  valueFormat = "_(*#,##0_);(*(#,##0);_(*\"-\");_(@_)"; break;
05468       case 43:  valueFormat = "_(\"$\"*#,##0.00_);_(\"$\"*#,##0.00_);_(\"$\"*\"-\");(@_)"; break;
05469       case 44:  valueFormat = "_(\"$\"*#,##0.00_);_(\"$\"*#,##0.00_);_(\"$\"*\"-\");(@_)"; break;
05470       case 45:  valueFormat = "mm:ss"; break;
05471       case 46:  valueFormat = "[h]:mm:ss"; break;
05472       case 47:  valueFormat = "mm:ss.0"; break;
05473       case 48:  valueFormat = "##0.0E+0"; break;
05474       case 49:  valueFormat = "@"; break;
05475       default: valueFormat = "General"; break;
05476     };
05477   format.setValueFormat( valueFormat );
05478     
05479   format.setFont( convertFont( xf.fontIndex() ) );
05480   
05481   FormatAlignment alignment;
05482   switch( xf.horizontalAlignment() )
05483   {
05484     case XFRecord::Left:     
05485       alignment.setAlignX( Format::Left ); break;
05486     case XFRecord::Right:    
05487       alignment.setAlignX( Format::Right ); break;
05488     case XFRecord::Centered: 
05489       alignment.setAlignX( Format::Center ); break;
05490     default: break;
05491     // FIXME still unsupported: Repeat, Justified, Filled, Distributed
05492   };
05493   switch( xf.verticalAlignment() )
05494   {
05495     case XFRecord::Top:
05496       alignment.setAlignY( Format::Top ); break;
05497     case XFRecord::VCentered:
05498       alignment.setAlignY( Format::Middle ); break;
05499     case XFRecord::Bottom:
05500       alignment.setAlignY( Format::Bottom ); break;
05501     default: break;
05502     // FIXME still unsupported: Justified, Distributed
05503   }
05504   alignment.setWrap( xf.textWrap() );
05505   format.setAlignment( alignment );
05506 
05507   FormatBorders borders;
05508     
05509   Pen pen;
05510   pen = convertBorderStyle( xf.leftBorderStyle() );
05511   pen.color = convertColor( xf.leftBorderColor() );
05512   borders.setLeftBorder( pen );
05513   
05514   pen = convertBorderStyle( xf.rightBorderStyle() );
05515   pen.color = convertColor( xf.rightBorderColor() );
05516   borders.setRightBorder( pen );
05517   
05518   pen = convertBorderStyle( xf.topBorderStyle() );
05519   pen.color = convertColor( xf.topBorderColor() );
05520   borders.setTopBorder( pen );
05521   
05522   pen = convertBorderStyle( xf.bottomBorderStyle() );
05523   pen.color = convertColor( xf.bottomBorderColor() );
05524   borders.setBottomBorder( pen );
05525   
05526   format.setBorders( borders );
05527 
05528   FormatBackground background;
05529   background.setForegroundColor( convertColor( xf.patternForeColor() ) );
05530   background.setBackgroundColor( convertColor( xf.patternBackColor() ) );
05531   background.setPattern( convertPatternStyle( xf.fillPattern() ) );
05532   format.setBackground( background );
05533 
05534   return format;
05535 }
05536 
05537 void ExcelReader::handleXF( XFRecord* record )
05538 {
05539   if( !record ) return;
05540   
05541   d->xfTable.push_back( *record );  
05542 }
05543 
05544 typedef std::vector<UString> UStringStack;
05545 
05546 void mergeTokens( UStringStack* stack, int count, UString mergeString )
05547 {
05548   if( !stack ) return;
05549   if( !stack->size() ) return;
05550   
05551   UString s1, s2;
05552     
05553   while(count)
05554   {
05555     count--;
05556     
05557     UString last = (*stack)[ stack->size()-1 ];
05558     UString tmp = last;
05559     tmp.append( s1 );
05560     s1 = tmp;
05561 
05562     if( count )
05563     {
05564       tmp = mergeString;
05565       tmp.append( s1 );
05566       s1 = tmp;
05567     }
05568 
05569     stack->resize( stack->size()-1 );
05570   }
05571 
05572   stack->push_back( s1 );
05573 }
05574 
05575 #ifdef SWINDER_XLS2RAW
05576 void dumpStack( std::vector<UString> stack )
05577 {
05578   std::cout << std::endl;
05579   std::cout << "Stack now is: " ;
05580   if( !stack.size() )
05581   std::cout << "(empty)" ;
05582  
05583   for( unsigned i = 0; i < stack.size(); i++ )
05584     std::cout << "  " << i << ": " << stack[i].ascii() << std::endl;
05585   std::cout << std::endl;
05586 }
05587 #endif
05588 
05589 UString ExcelReader::decodeFormula( unsigned row, unsigned col, const FormulaTokens& tokens )
05590 {
05591   UStringStack stack;
05592   
05593   for( unsigned c=0; c < tokens.size(); c++ )
05594   {
05595     FormulaToken token = tokens[c];
05596 
05597 #ifdef SWINDER_XLS2RAW
05598     std::cout << "Token " << c << ": ";
05599     std::cout <<  token.id() << "  "; 
05600     std::cout << token.idAsString() << std::endl;
05601 #endif
05602 
05603     switch( token.id() )
05604     {
05605       case FormulaToken::Add:  
05606         mergeTokens( &stack, 2, UString("+") );
05607         break;
05608         
05609       case FormulaToken::Sub:  
05610         mergeTokens( &stack, 2, UString("-") );
05611         break;
05612         
05613       case FormulaToken::Mul:  
05614         mergeTokens( &stack, 2, UString("*") );
05615         break;
05616         
05617       case FormulaToken::Div:  
05618         mergeTokens( &stack, 2, UString("/") );
05619         break;
05620         
05621       case FormulaToken::Power:  
05622         mergeTokens( &stack, 2, UString("^") );
05623         break;
05624         
05625       case FormulaToken::Concat:  
05626         mergeTokens( &stack, 2, UString("&") );
05627         break;
05628         
05629       case FormulaToken::LT:  
05630         mergeTokens( &stack, 2, UString("<") );
05631         break;
05632         
05633       case FormulaToken::LE:  
05634         mergeTokens( &stack, 2, UString("<=") );
05635         break;
05636         
05637       case FormulaToken::EQ:  
05638         mergeTokens( &stack, 2, UString("=") );
05639         break;
05640         
05641       case FormulaToken::GE:  
05642         mergeTokens( &stack, 2, UString(">=") );
05643         break;
05644         
05645       case FormulaToken::GT:  
05646         mergeTokens( &stack, 2, UString(">") );
05647         break;
05648         
05649       case FormulaToken::NE:  
05650         mergeTokens( &stack, 2, UString("<>") );
05651         break;
05652       
05653       case FormulaToken::Intersect:  
05654         mergeTokens( &stack, 2, UString(" ") );
05655         break;
05656         
05657       case FormulaToken::List:  
05658         mergeTokens( &stack, 2, UString(";") );
05659         break;
05660       
05661       case FormulaToken::Range:  
05662         mergeTokens( &stack, 2, UString(";") );
05663         break;
05664       
05665       case FormulaToken::UPlus:
05666         {
05667           UString str( "+" );
05668           str.append( stack[ stack.size()-1 ] );
05669           stack[ stack.size()-1 ] = str;
05670         }
05671         break;
05672     
05673       case FormulaToken::UMinus:  
05674         {
05675           UString str( "-" );
05676           str.append( stack[ stack.size()-1 ] );
05677           stack[ stack.size()-1 ] = str;
05678         }
05679         break;
05680     
05681       case FormulaToken::Percent:  
05682         stack[ stack.size()-1 ].append( UString("%") );
05683         break;
05684     
05685       case FormulaToken::Paren:  
05686         {
05687           UString str( "(" );
05688           str.append( stack[ stack.size()-1 ] );
05689           str.append( UString(")") );
05690           stack[ stack.size()-1 ] = str;
05691         }
05692         break;
05693     
05694       case FormulaToken::MissArg:
05695         // just ignore
05696         stack.push_back( UString(" ") );
05697         break;
05698     
05699       case FormulaToken::String:
05700         {
05701           UString str( '\"' );
05702           str.append( token.value().asString() );
05703           str.append( UString( '\"' ) );
05704           stack.push_back( str );
05705         }
05706         break;
05707     
05708       case FormulaToken::Bool:
05709         if( token.value().asBoolean() )
05710           stack.push_back( UString( "TRUE" ) );
05711         else  
05712           stack.push_back( UString( "FALSE" ) );
05713         break;
05714         
05715       case FormulaToken::Integer:
05716         stack.push_back( UString::from( token.value().asInteger() ) );
05717         break;
05718         
05719       case FormulaToken::Float:
05720         stack.push_back( UString::from( token.value().asFloat() ) );
05721         break;
05722         
05723       case FormulaToken::Array:
05724         // FIXME handle this !
05725         break;
05726       
05727       case FormulaToken::Ref:
05728         stack.push_back( token.ref( row, col ) );
05729         break;
05730       
05731       case FormulaToken::Area:
05732         stack.push_back( token.area( row, col ) );
05733         break;
05734 
05735       case FormulaToken::Function:
05736         {
05737           mergeTokens( &stack, token.functionParams(), UString(";") );
05738           if( stack.size() )
05739           {
05740             UString str( token.functionName() ? token.functionName() : "??" );
05741             str.append( UString("(") );
05742             str.append( stack[ stack.size()-1 ] );
05743             str.append( UString(")") );
05744             stack[ stack.size()-1 ] = str;
05745           }
05746         }
05747         break;
05748 
05749       case FormulaToken::FunctionVar:
05750         if( token.functionIndex() != 255 )
05751         {
05752           mergeTokens( &stack, token.functionParams(), UString(";") );
05753           if( stack.size() )
05754           {
05755             UString str;
05756             if( token.functionIndex() != 255 )
05757               str = token.functionName() ? token.functionName() : "??";
05758             str.append( UString("(") );
05759             str.append( stack[ stack.size()-1 ] );
05760             str.append( UString(")") );
05761             stack[ stack.size()-1 ] = str;
05762           }
05763         }
05764         else
05765         {
05766           unsigned count = token.functionParams()-1;
05767           mergeTokens( &stack, count, UString(";") );
05768           if( stack.size() )
05769           {
05770             UString str;
05771             str.append( UString("(") );
05772             str.append( stack[ stack.size()-1 ] );
05773             str.append( UString(")") );
05774             stack[ stack.size()-1 ] = str;
05775           }
05776         }
05777         break;
05778 
05779       case FormulaToken::Attr:
05780         if( token.attr() & 0x10 )  // SUM
05781         {
05782           mergeTokens( &stack, 1, UString(";") );
05783           if( stack.size() )
05784           {
05785             UString str( "SUM" );
05786             str.append( UString("(") );
05787             str.append( stack[ stack.size()-1 ] );
05788             str.append( UString(")") );
05789             stack[ stack.size()-1 ] = str;
05790           }
05791         }
05792         break;
05793 
05794       case FormulaToken::NameX:
05795         if( token.nameIndex() > 0 )
05796         if( token.nameIndex() <= d->nameTable.size() )
05797           stack.push_back( d->nameTable[ token.nameIndex()-1 ] );
05798         break;
05799 
05800       case FormulaToken::NatFormula:
05801       case FormulaToken::Sheet:
05802       case FormulaToken::EndSheet:
05803       case FormulaToken::ErrorCode:
05804       case FormulaToken::Name:
05805       case FormulaToken::MemArea:
05806       case FormulaToken::MemErr:
05807       case FormulaToken::MemNoMem:
05808       case FormulaToken::MemFunc:
05809       case FormulaToken::RefErr:
05810       case FormulaToken::AreaErr:
05811       case FormulaToken::RefN:
05812       case FormulaToken::AreaN:
05813       case FormulaToken::MemAreaN:
05814       case FormulaToken::MemNoMemN:
05815       case FormulaToken::Ref3d:
05816       case FormulaToken::Area3d:
05817       case FormulaToken::RefErr3d:
05818       case FormulaToken::AreaErr3d:
05819       default:
05820         // FIXME handle this !
05821         stack.push_back( UString("Unknown") );
05822         break;
05823     };
05824 
05825 #ifdef SWINDER_XLS2RAW
05826     dumpStack( stack );
05827 #endif
05828 
05829   }
05830   
05831   UString result;
05832   for( unsigned i = 0; i < stack.size(); i++ )
05833     result.append( stack[i] );
05834   
05835 #ifdef SWINDER_XLS2RAW
05836   std::cout << "FORMULA Result: " << result << std::endl;
05837 #endif
05838   return result;
05839 }
05840 
05841 
05842 #ifdef SWINDER_XLS2RAW
05843 
05844 #include <iostream>
05845 
05846 int main( int argc, char ** argv )
05847 {
05848   if( argc < 2 )
05849   {
05850     std::cout << "Usage: xls2raw filename" << std::endl;
05851     return 0;
05852   }
05853 
05854   char* filename = argv[1];
05855   std::cout << "Checking " << filename << std::endl;
05856   
05857   Workbook* workbook = new Workbook();
05858   ExcelReader* reader = new ExcelReader();
05859   reader->load( workbook, filename );
05860   delete reader;
05861   delete workbook;
05862     
05863   return 0;
05864 }
05865 
05866 #endif  // XLS2RAW
KDE Home | KDE Accessibility Home | Description of Access Keys