[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    koffice/filters/kspread/excel/sidewinder
From:       Marijn Kruisselbrink <m.kruisselbrink () student ! tue ! nl>
Date:       2009-10-30 13:40:35
Message-ID: 1256910035.456364.3816.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 1042677 by mkruisselbrink:

implement support for loading shared formulas (when the same formula is used in \
multiple cells excel only needs to save one copy of the actual formula). This adds \
support for the SHAREDFMLA record and the REFN formula token.


 M  +227 -5    excel.cpp  
 M  +48 -0     excel.h  


--- trunk/koffice/filters/kspread/excel/sidewinder/excel.cpp #1042676:1042677
@@ -40,6 +40,25 @@
   return ptr[0]+(ptr[1]<<8);
 }
 
+static inline long readS16( const void* p )
+{
+  long val = readU16( p );
+  if (val & 0x8000) {
+    val = val - 0x10000;
+  }
+  return val;
+}
+
+static inline long readS8( const void* p )
+{
+  const unsigned char* ptr = (const unsigned char*) p;
+  long val = *ptr;
+  if (val & 0x80) {
+    val = val - 0x100;
+  }
+  return val;
+}
+
 static inline unsigned long readU32( const void* p )
 {
   const unsigned char* ptr = (const unsigned char*) p;
@@ -270,12 +289,12 @@
     asianPhoneticsSize = readU32( data + offset );
     offset += 4;
   }
-  
+
   // find out total bytes used in this string
   unsigned size = offset;
   if( richText ) size += (formatRuns*4);
   if( asianPhonetics ) size += asianPhoneticsSize;
-  
+
   str = UString();
   for( unsigned k=0; k<len; k++ )
   {
@@ -1236,6 +1255,79 @@
   return result;
 }
 
+UString FormulaToken::refn( unsigned row, unsigned col ) const
+{
+  // FIXME check data size !
+  // FIXME handle shared formula
+  unsigned char buf[2];
+  int rowRef, colRef;
+  bool rowRelative, colRelative;
+
+  if( version() == Excel97 )
+  {
+    buf[0] = d->data[0];
+    buf[1] = d->data[1];
+    rowRef = readS16( buf );
+
+    buf[0] = d->data[2];
+    buf[1] = d->data[3];
+    colRef = readU16( buf );
+
+    rowRelative = colRef & 0x8000;
+    colRelative = colRef & 0x4000;
+    colRef &= 0xff;
+    if( colRef & 0x80 ) {
+      colRef = colRef - 0x100;
+    }
+  }
+  else
+  {
+    buf[0] = d->data[0];
+    buf[1] = d->data[1];
+    rowRef = readU16( buf );
+
+    buf[0] = d->data[2];
+    colRef = readS8( buf );
+
+    rowRelative = rowRef & 0x8000;
+    colRelative = rowRef & 0x4000;
+    rowRef &= 0x3fff;
+    if( rowRef & 0x2000 ) {
+      rowRef = rowRef - 0x4000;
+    }
+  }
+
+  colRef += col;
+  rowRef += row;
+
+  UString result;
+
+  result.append( UString("[") );  // OpenDocument format
+
+  if( !colRelative )
+    result.append( UString("$") );
+  result.append( Cell::columnLabel( colRef ) );
+  if( !rowRelative )
+    result.append( UString("$") );
+  result.append( UString::from( rowRef+1 ) );
+
+  result.append( UString("]") );// OpenDocument format
+
+  return result;
+}
+
+std::pair<unsigned, unsigned> FormulaToken::baseFormulaRecord() const
+{
+  if( version() == Excel97 )
+  {
+    return std::make_pair(readU16(&d->data[0]), readU16(&d->data[2]));
+  }
+  else
+  {
+    return std::make_pair(readU16(&d->data[0]), (unsigned)d->data[2]);
+  }
+}
+
 std::ostream& Swinder::operator<<( std::ostream& s,  Swinder::FormulaToken token )
 {
   s << std::setw(2) << std::hex << token.id() << std::dec;
@@ -1474,6 +1566,9 @@
   else if( type ==RStringRecord::id)
     return new RStringRecord();
 
+  else if( type ==SharedFormulaRecord::id)
+    return new SharedFormulaRecord();
+
   else if( type ==SSTRecord::id)
     return new SSTRecord();
 
@@ -1485,7 +1580,7 @@
 
   else if( type ==TopMarginRecord::id)
     return new TopMarginRecord();
-  
+
   return 0;
 }
 
@@ -2785,6 +2880,89 @@
 
 }
 
+
+// SHAREDFMLA
+
+const unsigned int SharedFormulaRecord::id = 0x04BC;
+
+class SharedFormulaRecord::Private
+{
+public:
+  // range
+  int numCells;
+  FormulaTokens tokens;
+};
+
+SharedFormulaRecord::SharedFormulaRecord():
+  Record()
+{
+  d = new SharedFormulaRecord::Private();
+}
+
+SharedFormulaRecord::~SharedFormulaRecord()
+{
+  delete d;
+}
+
+FormulaTokens SharedFormulaRecord::tokens() const
+{
+  return d->tokens;
+}
+
+void SharedFormulaRecord::setData( unsigned size, const unsigned char* data, const \
unsigned int* ) +{
+  if( size < 8 ) return;
+
+  // maybe read range
+  d->numCells = data[7];
+
+  unsigned formula_len = readU16( data+8 );
+
+  // reconstruct all tokens
+  d->tokens.clear();
+  for( unsigned j = 10; j < size; )
+  {
+    unsigned ptg = data[j++];
+    ptg = ((ptg & 0x40) ? (ptg | 0x20) : ptg) & 0x3F;
+    FormulaToken token( ptg );
+    token.setVersion( version() );
+
+    if( token.id() == FormulaToken::String )
+    {
+      // find bytes taken to represent the string
+      EString estr = (version()==Excel97) ?
+        EString::fromUnicodeString( data+j, false, formula_len ) :
+        EString::fromByteString( data+j, false, formula_len );
+      token.setData( estr.size(), data+j );
+      j += estr.size();
+    }
+    else
+    {
+      // normal, fixed-size token
+      if( token.size() > 1 )
+      {
+        token.setData( token.size(), data+j );
+        j += token.size();
+      }
+    }
+
+    d->tokens.push_back( token );
+  }
+}
+
+void SharedFormulaRecord::dump( std::ostream& out ) const
+{
+  out << "SHAREDFMLA" << std::endl;
+  // range
+  out << "          Num cells : " << d->numCells << std::endl;
+
+  FormulaTokens ts = tokens();
+  out << "             Tokens : " << ts.size() << std::endl;
+  for( unsigned i = 0; i < ts.size(); i++ )
+    out << "                       " << ts[i]  << std::endl;
+
+}
+
 // ========== LABEL ==========
 
 const unsigned int LabelRecord::id = 0x0204;
@@ -4446,6 +4624,12 @@
 
   // for NAME and EXTERNNAME
   std::vector<UString> nameTable;
+
+  // mapping from cell position to shared formulas
+  std::map<std::pair<unsigned, unsigned>, FormulaTokens> sharedFormulas;
+
+  // for FORMULA+SHAREDFMLA record pair
+  Cell* lastFormulaCell;
 };
 
 ExcelReader::ExcelReader()
@@ -4455,6 +4639,7 @@
   d->workbook    = 0;
   d->activeSheet = 0;
   d->formulaCell = 0;
+  d->lastFormulaCell = 0;
 
   d->passwordProtected = false;
 
@@ -4513,7 +4698,7 @@
   unsigned char small_buffer[128];	// small, fixed size buffer
   unsigned int continuePositionsSize = 128; // size of array for continue positions
   unsigned int *continuePositions = (unsigned int *) malloc(continuePositionsSize * \
                sizeof(int));
-  
+
   workbook->clear();
   d->workbook = workbook;
 
@@ -4715,6 +4900,8 @@
       handleRow( static_cast<RowRecord*>( record ) ); break;
     case RStringRecord::id:
       handleRString( static_cast<RStringRecord*>( record ) ); break;
+    case SharedFormulaRecord::id:
+      handleSharedFormula( static_cast<SharedFormulaRecord*>( record ) ); break;
     case SSTRecord::id:
       handleSST( static_cast<SSTRecord*>( record ) ); break;
     case StringRecord::id:
@@ -4918,6 +5105,7 @@
     // if value is string, real value is in subsequent String record
     if( value.isString() )
       d->formulaCell = cell;
+    d->lastFormulaCell = cell;
   }
 }
 
@@ -5245,6 +5433,22 @@
   }
 }
 
+void ExcelReader::handleSharedFormula( SharedFormulaRecord* record )
+{
+  if( !record ) return;
+  if( !d->lastFormulaCell ) return;
+
+  unsigned row = d->lastFormulaCell->row();
+  unsigned column = d->lastFormulaCell->column();
+
+  d->sharedFormulas[std::make_pair(row, column)] = record->tokens();
+
+  UString formula = decodeFormula( row, column, record->tokens() );
+  d->lastFormulaCell->setFormula( formula );
+
+  d->lastFormulaCell = 0;
+}
+
 void ExcelReader::handleSST( SSTRecord* record )
 {
   if( !record ) return;
@@ -5747,6 +5951,10 @@
         stack.push_back( token.ref( row, col ) );
         break;
 
+      case FormulaToken::RefN:
+        stack.push_back( token.refn( row, col ) );
+        break;
+
       case FormulaToken::Area:
         stack.push_back( token.area( row, col ) );
         break;
@@ -5816,6 +6024,21 @@
           stack.push_back( d->nameTable[ token.nameIndex()-1 ] );
         break;
 
+      case FormulaToken::Matrix: {
+        std::pair<unsigned, unsigned> formulaCellPos = token.baseFormulaRecord();
+
+        std::map<std::pair<unsigned, unsigned>, FormulaTokens>::iterator \
sharedFormula = d->sharedFormulas.find(formulaCellPos); +        if( sharedFormula != \
d->sharedFormulas.end() ) +        {
+          stack.push_back(decodeFormula(row, col, sharedFormula->second));
+        }
+        else
+        {
+          stack.push_back(UString("Error"));
+        }
+        break;
+      }
+
       case FormulaToken::NatFormula:
       case FormulaToken::Sheet:
       case FormulaToken::EndSheet:
@@ -5827,7 +6050,6 @@
       case FormulaToken::MemFunc:
       case FormulaToken::RefErr:
       case FormulaToken::AreaErr:
-      case FormulaToken::RefN:
       case FormulaToken::AreaN:
       case FormulaToken::MemAreaN:
       case FormulaToken::MemNoMemN:
--- trunk/koffice/filters/kspread/excel/sidewinder/excel.h #1042676:1042677
@@ -170,6 +170,8 @@
 
   // only when id is Ref
   UString ref( unsigned row, unsigned col ) const;
+  // only when id is RefN
+  UString refn( unsigned row, unsigned col ) const;
 
   // only when id is Area
   UString area( unsigned row, unsigned col ) const;
@@ -180,6 +182,9 @@
   // only when id is NameX
   unsigned nameIndex() const;
 
+  // only when id is Matrix (tExp)
+  std::pair<unsigned, unsigned> baseFormulaRecord() const;
+
 private:
   class Private;
   Private *d;
@@ -1586,7 +1591,49 @@
   Private* d;
 };
 
+
 /**
+  \brief Shared Formula.
+
+  Information about a shared formula, the formula itself and its range.
+ */
+class SharedFormulaRecord : public Record
+{
+public:
+  static const unsigned int id;
+
+  unsigned int rtti(){
+      return this->id;
+  }
+
+  /**
+   * Creates a new shared formula record.
+   */
+  SharedFormulaRecord();
+
+  /**
+   * Destroy the record.
+   */
+  ~SharedFormulaRecord();
+
+  FormulaTokens tokens() const;
+
+  virtual void setData( unsigned size, const unsigned char* data, const unsigned \
int* continuePositions  ); +
+  virtual const char* name(){ return "SHAREDFMLA"; }
+
+  virtual void dump( std::ostream& out ) const;
+
+private:
+  // no copy or assign
+  SharedFormulaRecord( const SharedFormulaRecord& );
+  SharedFormulaRecord& operator=( const SharedFormulaRecord& );
+
+  class Private;
+  Private* d;
+};
+
+/**
   \brief Sheet header.
 
   Class HeaderRecord holds information about sheet header.
@@ -3113,6 +3160,7 @@
   void handleRString( RStringRecord* record );
   void handleRK( RKRecord* record );
   void handleRow( RowRecord* record );
+  void handleSharedFormula( SharedFormulaRecord* sharedFormulaRecord );
   void handleSST( SSTRecord* record );
   void handleString( StringRecord* record );
   void handleTopMargin( TopMarginRecord* record );


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic