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