/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* This file is part of libxls -- A multiplatform, C/C++ library
* for parsing Excel(TM) files.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY David Hoerl ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David Hoerl OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 2014 David Hoerl
*
*/
#include <stdio.h>
#include <assert.h>
#include "xlsformula.h"
//#include <libxls/xls.h>
static void dump_formula_formula(WORD len, BYTE *buf);
static void dump_formula_array(WORD len, BYTE *buf);
static void dump_formula_data(WORD len, BYTE *buf);
static WORD func_len(WORD func);
static WORD get_token_size(BYTE *buf);
typedef struct { const char *xlsName; const char *excelName; } excelNames;
static const excelNames tokenNames[128];
static const excelNames functionNames[368];
static unsigned short xlsShortVal (short s);
void dump_formula(WORD bof, WORD len, BYTE *buf)
{
if(bof == 0x0221) {
dump_formula_array(len, buf);
} else {
dump_formula_formula(len, buf);
}
}
static void dump_formula_formula(WORD len, BYTE *buf)
{
FORMULA *f = (FORMULA *)buf;
printf("FORMULA LEN: %d\n", len);
printf("ROW: %d\n", f->row);
printf("COL: %d\n", f->col);
printf("NUM: "); for(int i=-1; i<7; ++i) printf("%2.2x ", f->resdata[i]); printf("\n");
printf("OPTIONS: 0x%x\n", f->flags);
dump_formula_data(f->len, f->value);
}
static void dump_formula_array(WORD len, BYTE *buf)
{
FARRAY *f = (FARRAY *)buf;
printf("FORMULA ARRAY LEN: %d\n", len);
printf("ROW: %d->%d\n", f->row1, f->row2);
printf("COL: %d->%d\n", f->col1, f->col2);
printf("OPTIONS: 0x%x\n", f->flags);
dump_formula_data(f->len, f->value);
}
static void dump_formula_data(WORD flen, BYTE *buf)
{
printf("FORMULA LEN: %d\n", flen);
if(flen) {
#if 0
printf(" ");
for(int i=0; i<f->len; ++i) printf("%2.2x ", buf[i]);
printf("\n");
#endif
BYTE *b = buf;
while((b-buf) < flen) {
WORD len = get_token_size(b);
if(!len) {
printf("YIKES: token 0x%2.2x no len!\n", b[0]);
return;
}
int printBytes = 1;
excelNames tn = tokenNames[ b[0] ];
switch(b[0]) {
case 0x21:
case 0x41:
case 0x61:
{
unsigned short func = xlsShortVal(*(short *)&b[1]);
excelNames fn = functionNames[ func ];
printf("%s (0x%x) %s", tn.xlsName, b[0], fn.xlsName);
printBytes = 0;
} break;
case 0x22:
case 0x42:
case 0x62:
{
unsigned short func = xlsShortVal(*(short *)&b[2]);
excelNames fn = functionNames[ func ];
printf("%s (0x%x) %s arguments=%d", tn.xlsName, b[0], fn.xlsName, b[1]);
printBytes = 0;
} break;
case 0x24:
case 0x44:
case 0x64:
{
unsigned short col = xlsShortVal(*(short *)&b[3]);
unsigned short flags = col & 0xC000;
col &= ~0xC000;
printf("%s (0x%x) ROW=%d COL=%d FLAGS=0x%x", tn.xlsName, b[0], xlsShortVal(*(short *)&b[1]), col, flags );
printBytes = 0;
} break;
default:
//printf("TOKEN[0x%x]: ", b[0]);
printf("%s (0x%x): ", tn.xlsName, b[0]);
break;
}
if(printBytes) {
for(int i=1; i<len; ++i) printf("%2.2x ", b[i]);
}
printf("\n");
b += len;
}
}
}
// From "Open Office MS Excel File Format", pg 42-43
static WORD token_size[128] = {
0,
5,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
0,
0,
2,
2,
3,
9,
8,
3,
4,
5,
5,
9,
7,
7,
7,
3,
5,
9,
5,
9,
3,
3,
0,
0,
0,
0,
0,
0,
0,
0,
0,
7,
7,
11,
7,
11,
0,
0,
8,
3,
4,
5,
5,
9,
7,
7,
7,
3,
5,
9,
5,
9,
3,
3,
0,
0,
0,
0,
0,
0,
0,
0,
0,
7,
7,
11,
7,
11,
0,
0,
8,
3,
4,
5,
5,
9,
7,
7,
7,
3,
5,
9,
5,
9,
3,
3,
0,
0,
0,
0,
0,
0,
0,
0,
0,
7,
7,
11,
7,
11,
0,
0,
};
static WORD get_token_size(BYTE *buf)
{
WORD len = token_size[buf[0]];
if(!len) {
switch(buf[0]) {
case 0x19:
{
BYTE flag = buf[1];
switch(flag) {
case 0x00: // only in original OSX Excel circa 2001
case 0x01:
case 0x02:
len = 4;
break;
case 0x04: // not handled
break;
case 0x08:
case 0x10:
case 0x20:
case 0x40:
case 0x41:
len = 4;
break;
}
if(!len) printf("YIKES: 0x19 with flag 0x%2.2x\n", flag);
} break;
default:
break;
}
}
return len;
}
static const excelNames tokenNames[128] = {
{ "", "" }, // 0x00 (0)
{ "OP_EXP", "ptgExp" }, // 0x01 (1)
{ "OP_TBL", "ptgTbl" }, // 0x02 (2)
{ "OP_ADD", "ptgAdd" }, // 0x03 (3)
{ "OP_SUB", "ptgSub" }, // 0x04 (4)
{ "OP_MUL", "ptgMul" }, // 0x05 (5)
{ "OP_DIV", "ptgDiv" }, // 0x06 (6)
{ "OP_POWER", "ptgPower" }, // 0x07 (7)
{ "OP_CONCAT", "ptgConcat" }, // 0x08 (8)
{ "OP_LT", "ptgLT" }, // 0x09 (9)
{ "OP_LE", "ptgLE" }, // 0x0a (10)
{ "OP_EQ", "ptgEQ" }, // 0x0b (11)
{ "OP_GE", "ptgGE" }, // 0x0c (12)
{ "OP_GT", "ptgGT" }, // 0x0d (13)
{ "OP_NE", "ptgNE" }, // 0x0e (14)
{ "OP_ISECT", "ptgIsect" }, // 0x0f (15)
{ "OP_UNION", "ptgUnion" }, // 0x10 (16)
{ "OP_RANGE", "ptgRange" }, // 0x11 (17)
{ "OP_UPLUS", "ptgUplus" }, // 0x12 (18)
{ "OP_UMINUS", "ptgUminus" }, // 0x13 (19)
{ "OP_PERCENT", "ptgPercent" }, // 0x14 (20)
{ "OP_PAREN", "ptgParen" }, // 0x15 (21)
{ "OP_MISSARG", "ptgMissArg" }, // 0x16 (22)
{ "OP_STR", "ptgStr" }, // 0x17 (23)
{ "", "" }, // 0x18 (24)
{ "OP_ATTR", "ptgAttr" }, // 0x19 (25)
{ "OP_SHEET", "ptgSheet" }, // 0x1a (26)
{ "OP_ENDSHEET", "ptgEndSheet" }, // 0x1b (27)
{ "OP_ERR", "ptgErr" }, // 0x1c (28)
{ "OP_BOOL", "ptgBool" }, // 0x1d (29)
{ "OP_INT", "ptgInt" }, // 0x1e (30)
{ "OP_NUM", "ptgNum" }, // 0x1f (31)
{ "OP_ARRAY", "ptgArray" }, // 0x20 (32)
{ "OP_FUNC", "ptgFunc" }, // 0x21 (33)
{ "OP_FUNCVAR", "ptgFuncVar" }, // 0x22 (34)
{ "OP_NAME", "ptgName" }, // 0x23 (35)
{ "OP_REF", "ptgRef" }, // 0x24 (36)
{ "OP_AREA", "ptgArea" }, // 0x25 (37)
{ "OP_MEMAREA", "ptgMemArea" }, // 0x26 (38)
{ "OP_MEMERR", "ptgMemErr" }, // 0x27 (39)
{ "OP_MEMNOMEM", "ptgMemNoMem" }, // 0x28 (40)
{ "OP_MEMFUNC", "ptgMemFunc" }, // 0x29 (41)
{ "OP_REFERR", "ptgRefErr" }, // 0x2a (42)
{ "OP_AREAERR", "ptgAreaErr" }, // 0x2b (43)
{ "OP_REFN"