Commit d144c177 authored by Morten Welinder's avatar Morten Welinder Committed by Morten Welinder
Browse files

Handle some wk4 records.

2005-10-18  Morten Welinder  <terra@gnome.org>

	* lotus.c (lotus_read_new): Handle some wk4 records.
parent b9194856
......@@ -7,6 +7,7 @@ Morten:
* Fix content probing of csv and tsv files. [#318419]
* Import formats from Lotus 1-2-3 files.
* Import column widths and row heights from Lotus 1-2-3 files.
* Read basic info from wk4 files.
--------------------------------------------------------------------------
Gnumeric 1.6.0
......
2005-10-18 Morten Welinder <terra@gnome.org>
* lotus.c (lotus_read_new): Handle some wk4 records.
2005-10-13 Morten Welinder <terra@gnome.org>
* lotus.c (lotus_set_rowheight_cb, lotus_set_colwidth_cb,
......
......@@ -55,9 +55,11 @@ lotus_file_probe (GOFileOpener const *fo, GsfInput *input, FileProbeLevel pl)
case LOTUS_VERSION_SYMPHONY:
return len == 2;
case LOTUS_VERSION_123V4: /* Barely and crudely handled. */
case LOTUS_VERSION_123V6:
case LOTUS_VERSION_123V7:
case LOTUS_VERSION_123SS98:
return TRUE;
return len >= 19;
default:
return FALSE;
......
......@@ -388,7 +388,9 @@ get_cellref (GnmCellRef *ref, guint8 const *dataa, guint8 const *datab,
}
#if FORMULA_DEBUG > 0
printf ("0x%x 0x%x -> (%d, %d)\n", *(guint16 *)dataa, *(guint16 *)datab,
printf ("0x%x 0x%x -> (%d, %d)\n",
GSF_LE_GET_GUINT16 (dataa),
GSF_LE_GET_GUINT16 (datab),
ref->col, ref->row);
#endif
}
......@@ -444,10 +446,6 @@ lotus_parse_formula_old (LotusState *state, GnmParsePos *orig,
i += 2 + strlen (data + i + 1);
break;
case LOTUS_FORMULA_UNARY_PLUS:
i++;
break;
default:
i += make_function (&stack, data + i, orig);
}
......@@ -520,6 +518,7 @@ lotus_parse_formula_new (LotusState *state, GnmParsePos *orig,
GnmExprList *stack = NULL;
guint i;
gboolean done = FALSE;
gboolean uses_snum = (state->version <= LOTUS_VERSION_123V4);
for (i = 0; i < len && !done;) {
switch (data[i]) {
......@@ -565,15 +564,16 @@ lotus_parse_formula_new (LotusState *state, GnmParsePos *orig,
break;
case LOTUS_FORMULA_PACKED_NUMBER: {
double v = lotus_unpack_number (GSF_LE_GET_GUINT32 (data + i + 1));
GnmValue *val;
if (uses_snum) {
val = lotus_smallnum (GSF_LE_GET_GUINT16 (data + i + 1));
i += 3;
} else {
val = lotus_unpack_number (GSF_LE_GET_GUINT32 (data + i + 1));
i += 5;
}
if (v == gnm_floor (v) && v >= G_MININT && v <= G_MAXINT)
val = value_new_int ((int)v);
else
val = value_new_float (v);
parse_list_push_value (&stack, val);
i += 5;
break;
}
......@@ -674,7 +674,7 @@ GnmExpr const *
lotus_parse_formula (LotusState *state, GnmParsePos *pos,
guint8 const *data, guint32 len)
{
const GnmExpr *result = (state->version >= LOTUS_VERSION_123V6)
const GnmExpr *result = (state->version >= LOTUS_VERSION_123V4)
? lotus_parse_formula_new (state, pos, data, len)
: lotus_parse_formula_old (state, pos, data, len);
......
......@@ -12,11 +12,6 @@
#define LOTUS_FORMULA_INTEGER 0x5
#define LOTUS_FORMULA_STRING 0x6
#define LOTUS_FORMULA_LOGICAL_AND 0x14
#define LOTUS_FORMULA_LOGICAL_OR 0x15
#define LOTUS_FORMULA_UNARY_PLUS 0x17
#define LOTUS_FORMULA_PACKED_NUMBER 0x5
#define LOTUS_FORMULA_NAMED 0x7
#define LOTUS_FORMULA_ABS_NAMED 0x8
......
......@@ -45,6 +45,8 @@
#define LOTUS_ERRCELL 0x14
#define LOTUS_NACELL 0x15
#define LOTUS_LABEL2 0x16
#define LOTUS_SMALLNUM 0x18 /* wk3,wk4 */
#define LOTUS_FORMULA3 0x19 /* wk3,wk4 */
#define LOTUS_STYLE 0x1b
#define LOTUS_DTLABELMISC 0x1c
#define LOTUS_CPA 0x1f
......
......@@ -769,6 +769,140 @@ lotus_qmps_to_points (guint qmps)
/* ------------------------------------------------------------------------- */
typedef struct {
GsfInput *input;
guint16 type;
guint16 len;
guint8 const *data;
} record_t;
static void
report_record_size_error (LotusState *state, record_t *r)
{
g_warning ("Record with type 0x%x has wrong length %d.",
r->type, r->len);
/* FIXME: mark the error in the state instead. */
}
#define CHECK_RECORD_SIZE(cond) \
if (!(r->len cond)) { \
report_record_size_error (state, r); \
break; \
} else
static guint16
record_peek_next (record_t *r)
{
guint8 const *header;
guint16 type;
g_return_val_if_fail (r != NULL, LOTUS_EOF);
header = gsf_input_read (r->input, 2, NULL);
if (header == NULL)
return 0xffff;
type = GSF_LE_GET_GUINT16 (header);
gsf_input_seek (r->input, -2, G_SEEK_CUR);
return type;
}
static gboolean
record_next (record_t *r)
{
guint8 const *header;
g_return_val_if_fail (r != NULL, FALSE);
header = gsf_input_read (r->input, 4, NULL);
if (header == NULL)
return FALSE;
r->type = GSF_LE_GET_GUINT16 (header);
r->len = GSF_LE_GET_GUINT16 (header + 2);
r->data = (r->len == 0
? (void *)""
: gsf_input_read (r->input, r->len, NULL));
#if LOTUS_DEBUG > 0
g_print ("Record 0x%x length 0x%x\n", r->type, r->len);
if (r->data)
gsf_mem_dump (r->data, r->len);
#endif
return (r->data != NULL);
}
/* ------------------------------------------------------------------------- */
static GnmValue *
lotus_value (gnm_float v)
{
if (v == gnm_floor (v) &&
v >= G_MININT &&
v <= G_MAXINT)
return value_new_int ((int)v);
else
return value_new_float (v);
}
static GnmValue *
lotus_lnumber (const record_t *r, int ofs)
{
const guint8 *p;
g_return_val_if_fail (ofs + 8 <= r->len, NULL);
p = r->data + ofs;
/* FIXME: Some special values indicate ERR, NA, BLANK, and string. */
return lotus_value (gsf_le_get_double (p));
}
GnmValue *
lotus_unpack_number (guint32 u)
{
double v = (u >> 6);
if (u & 0x20) v = 0 - v;
if (u & 0x10)
return lotus_value (v / gnm_pow10 (u & 15));
else
return lotus_value (v * gnm_pow10 (u & 15));
}
GnmValue *
lotus_smallnum (signed int d)
{
if (d & 1) {
static int factors[8] = {
5000, 500, -20, -200, -2000, -20000, -16, -64
};
int f = factors[(d >> 1) & 7];
int mant = (d >> 4);
return (f > 0)
? value_new_int (f * mant)
: lotus_value ((gnm_float)mant / -f);
} else
return value_new_int (d >> 1);
}
static GnmValue *
lotus_treal (const record_t *r, int ofs)
{
const guint8 *p;
gnm_float v;
g_return_val_if_fail (ofs + 10 <= r->len, NULL);
p = r->data + ofs;
/* This this ignores two bytes of mantissa. */
v = GSF_LE_GET_DOUBLE (p + 2);
return lotus_value (v);
}
/* ------------------------------------------------------------------------- */
typedef struct _LotusRLDB LotusRLDB;
struct _LotusRLDB {
......@@ -1308,72 +1442,6 @@ lotus_rldb_apply (LotusRLDB *rldb, int type, LotusState *state)
/* ------------------------------------------------------------------------- */
typedef struct {
GsfInput *input;
guint16 type;
guint16 len;
guint8 const *data;
} record_t;
static void
report_record_size_error (LotusState *state, record_t *r)
{
g_warning ("Record with type 0x%x has wrong length %d.",
r->type, r->len);
/* FIXME: mark the error in the state instead. */
}
#define CHECK_RECORD_SIZE(cond) \
if (!(r->len cond)) { \
report_record_size_error (state, r); \
break; \
} else
static guint16
record_peek_next (record_t *r)
{
guint8 const *header;
guint16 type;
g_return_val_if_fail (r != NULL, LOTUS_EOF);
header = gsf_input_read (r->input, 2, NULL);
if (header == NULL)
return 0xffff;
type = GSF_LE_GET_GUINT16 (header);
gsf_input_seek (r->input, -2, G_SEEK_CUR);
return type;
}
static gboolean
record_next (record_t *r)
{
guint8 const *header;
g_return_val_if_fail (r != NULL, FALSE);
header = gsf_input_read (r->input, 4, NULL);
if (header == NULL)
return FALSE;
r->type = GSF_LE_GET_GUINT16 (header);
r->len = GSF_LE_GET_GUINT16 (header + 2);
r->data = (r->len == 0
? (void *)""
: gsf_input_read (r->input, r->len, NULL));
#if LOTUS_DEBUG > 0
g_print ("Record 0x%x length 0x%x\n", r->type, r->len);
if (r->data)
gsf_mem_dump (r->data, r->len);
#endif
return (r->data != NULL);
}
static GnmCell *
insert_value (Sheet *sheet, guint32 col, guint32 row, GnmValue *val)
{
......@@ -1421,6 +1489,8 @@ lotus_read_old (LotusState *state, record_t *r)
int sheetidx = 0;
GnmCell *cell;
state->lmbcs_group = 1;
do {
switch (r->type) {
case LOTUS_BOF:
......@@ -1443,7 +1513,7 @@ lotus_read_old (LotusState *state, record_t *r)
break;
}
case LOTUS_NUMBER: CHECK_RECORD_SIZE (>= 13) {
GnmValue *v = value_new_float (gsf_le_get_double (r->data + 5));
GnmValue *v = lotus_value (gsf_le_get_double (r->data + 5));
guint8 fmt = GSF_LE_GET_GUINT8 (r->data);
int i = GSF_LE_GET_GUINT16 (r->data + 1);
int j = GSF_LE_GET_GUINT16 (r->data + 3);
......@@ -1498,7 +1568,7 @@ lotus_read_old (LotusState *state, record_t *r)
} else
v = value_new_error_VALUE (NULL);
} else
v = value_new_float (gsf_le_get_double (r->data + 5));
v = lotus_value (gsf_le_get_double (r->data + 5));
cell = sheet_cell_fetch (state->sheet, col, row);
cell_set_expr_and_value (cell, expr, v, TRUE);
......@@ -1698,37 +1768,6 @@ lotus_new_string (gchar const *data)
(lotus_get_lmbcs (data, strlen (data)));
}
double
lotus_unpack_number (guint32 u)
{
double v = (u >> 6);
if (u & 0x20) v = 0 - v;
if (u & 0x10)
v = v / gnm_pow10 (u & 15);
else
v = v * gnm_pow10 (u & 15);
return v;
}
static GnmValue *
get_lnumber (const record_t *r, int ofs)
{
const guint8 *p;
g_return_val_if_fail (ofs + 8 <= r->len, NULL);
p = r->data + ofs;
/* FIXME: Some special values indicate ERR, NA, BLANK, and string. */
if (1) {
double v = gsf_le_get_double (p);
return value_new_float (v);
}
}
static gboolean
lotus_read_new (LotusState *state, record_t *r)
{
......@@ -1747,8 +1786,13 @@ lotus_read_new (LotusState *state, record_t *r)
do {
switch (r->type) {
case LOTUS_BOF:
case LOTUS_BOF: CHECK_RECORD_SIZE (>= 18) {
state->lmbcs_group = GSF_LE_GET_GUINT8 (r->data + 16);
if (state->lmbcs_group != 1)
g_warning ("Unhandled character set setting (%d)",
state->lmbcs_group);
break;
}
case LOTUS_EOF:
goto done;
......@@ -1786,7 +1830,16 @@ lotus_read_new (LotusState *state, record_t *r)
int row = GSF_LE_GET_GUINT16 (r->data);
Sheet *sheet = lotus_get_sheet (state->wb, r->data[2]);
int col = r->data[3];
GnmValue *v = get_lnumber (r, 4);
GnmValue *v = lotus_lnumber (r, 4);
(void)insert_value (sheet, col, row, v);
break;
}
case LOTUS_SMALLNUM: CHECK_RECORD_SIZE (>= 6) {
int row = GSF_LE_GET_GUINT16 (r->data);
Sheet *sheet = lotus_get_sheet (state->wb, r->data[2]);
int col = r->data[3];
GnmValue *v = lotus_smallnum (GSF_LE_GET_GINT16 (r->data + 4));
(void)insert_value (sheet, col, row, v);
break;
}
......@@ -1927,16 +1980,7 @@ lotus_read_new (LotusState *state, record_t *r)
int row = GSF_LE_GET_GUINT16 (r->data);
Sheet *sheet = lotus_get_sheet (state->wb, r->data[2]);
int col = r->data[3];
double v = lotus_unpack_number (GSF_LE_GET_GUINT32 (r->data + 4));
GnmValue *val;
if (v == gnm_floor (v) &&
v >= G_MININT &&
v <= G_MAXINT)
val = value_new_int ((int)v);
else
val = value_new_float (v);
GnmValue *val = lotus_unpack_number (GSF_LE_GET_GUINT32 (r->data + 4));
(void)insert_value (sheet, col, row, val);
break;
}
......@@ -1962,7 +2006,7 @@ lotus_read_new (LotusState *state, record_t *r)
int row = GSF_LE_GET_GUINT16 (r->data);
Sheet *sheet = lotus_get_sheet (state->wb, r->data[2]);
int col = r->data[3];
GnmValue *curval = get_lnumber (r, 4);
GnmValue *curval = lotus_lnumber (r, 4);
GnmParsePos pp;
const GnmExpr *expr;
GnmCell *cell;
......@@ -1980,6 +2024,28 @@ lotus_read_new (LotusState *state, record_t *r)
break;
}
case LOTUS_FORMULA3: CHECK_RECORD_SIZE (>= 15) {
int row = GSF_LE_GET_GUINT16 (r->data);
Sheet *sheet = lotus_get_sheet (state->wb, r->data[2]);
int col = r->data[3];
GnmValue *curval = lotus_treal (r, 4);
GnmParsePos pp;
const GnmExpr *expr;
GnmCell *cell;
pp.eval.col = col;
pp.eval.row = row;
pp.sheet = sheet;
pp.wb = sheet->workbook;
expr = lotus_parse_formula (state, &pp,
r->data + 14, r->len - 14);
cell = sheet_cell_fetch (sheet, col, row);
cell_set_expr_and_value (cell, expr, curval, TRUE);
gnm_expr_unref (expr);
break;
}
case LOTUS_CA_DB:
case LOTUS_DEFAULTS_DB:
case LOTUS_NAMED_STYLE_DB:
......@@ -2182,7 +2248,9 @@ lotus_read (LotusState *state)
default:
g_warning ("Unexpected version %x", state->version);
/* Fall through. */
case LOTUS_VERSION_123V4:
case LOTUS_VERSION_123V6:
case LOTUS_VERSION_123V7:
case LOTUS_VERSION_123SS98:
return lotus_read_new (state, &r);
}
......
......@@ -7,7 +7,9 @@
typedef enum {
LOTUS_VERSION_ORIG_123 = 0x0404,
LOTUS_VERSION_SYMPHONY = 0x0405,
LOTUS_VERSION_123V4 = 0x1002,
LOTUS_VERSION_123V6 = 0x1003,
LOTUS_VERSION_123V7 = 0x1004, /* Not sure. */
LOTUS_VERSION_123SS98 = 0x1005
} LotusVersion;
......@@ -18,14 +20,16 @@ typedef struct {
Workbook *wb;
Sheet *sheet;
LotusVersion version;
guint8 lmbcs_group;
GHashTable *style_pool;
} LotusState;
Sheet *lotus_get_sheet (Workbook *wb, int i);
double lotus_unpack_number (guint32 u);
char *lotus_get_lmbcs (const char *data, int maxlen);
GnmValue *lotus_new_string (gchar const *data);
gboolean lotus_read (LotusState *state);
gboolean lotus_read (LotusState *state);
GnmValue *lotus_unpack_number (guint32 u);
GnmValue *lotus_smallnum (signed int d);
#endif
......@@ -14,6 +14,7 @@
</information>
<suffixes>
<suffix>wk1</suffix>
<suffix>wk4</suffix>
<suffix>wks</suffix>
<suffix>123</suffix>
</suffixes>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment