filters

excel.cpp

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