[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