--- psiconv/trunk/lib/psiconv/parse_formula.c 2001/01/30 23:57:28 101 +++ psiconv/trunk/lib/psiconv/parse_formula.c 2001/02/02 21:07:11 105 @@ -291,20 +291,169 @@ {psiconv_formula_unknown,0,"*UNKNOWN*"}, {psiconv_formula_unknown,0,"*UNKNOWN*"}}; -int psiconv_parse_formula(const psiconv_buffer buf, int lev, - psiconv_u32 off, int *length, - psiconv_formula *result) +static psiconv_string_t psiconv_read_sheet_string(const psiconv_buffer buf, + int lev, + psiconv_u32 off,int *length, int *status) +{ + int stringlen,i,len,localstatus; + psiconv_string_t result; + char *res_copy; + + psiconv_progress(lev+1,off,"Going to read a sheet string"); + + stringlen = psiconv_read_u8(buf,lev+2,off,&localstatus); + if (localstatus) + goto ERROR1; + psiconv_debug(lev+2,off,"Length: %i",stringlen); + len = 1; + + result = malloc(stringlen + 1); + if (!result) + goto ERROR1; + for (i = 0; (i < stringlen) && !localstatus; i++) + result[i] = psiconv_read_u8(buf,lev,off+i+len,&localstatus); + if (localstatus) + goto ERROR2; + result[stringlen] = 0; + len += stringlen; + + res_copy = psiconv_make_printable(result); + if (!res_copy) + goto ERROR2; + psiconv_debug(lev+2,off,"Contents: `%s'",res_copy); + free(res_copy); + + if (length) + *length = len; + + if (status) + *status = 0; + + psiconv_progress(lev+1,off+len-1,"End of sheet string (total length: %08x)", + len); + + return result; + + +ERROR2: + free(result); +ERROR1: + psiconv_warn(lev+1,off,"Reading of sheet string failed"); + if (status) + *status = localstatus; + if (length) + *length = 0; + return NULL; +} + + +static int psiconv_parse_sheet_ref(const psiconv_buffer buf,int lev, + psiconv_u32 off, int *length, + psiconv_sheet_ref_t *result) +{ + int res; + psiconv_u16 temp; + + psiconv_progress(lev+1,off,"Going to read a sheet ref"); + psiconv_progress(lev+2,off,"Going to read the offset encoding"); + temp = psiconv_read_u16(buf,lev+2,off,&res); + if (res) { + if (length) + *length = 0; + return res; + } + psiconv_debug(lev+2,off,"Encoded word: %04x",temp); + result->absolute = (temp & 0x4000)?psiconv_bool_true:psiconv_bool_false; + result->offset = (temp & 0x3fff) * ((temp & 0x8000)?-1:1); + psiconv_debug(lev+2,off,"Reference: %s offset %d", + result->absolute?"absolute":"relative",result->offset); + if (length) + *length = 2; + return 0; +} + +static int psiconv_parse_sheet_cell_reference(const psiconv_buffer buf,int lev, + psiconv_u32 off, int *length, + psiconv_sheet_cell_reference_t *result) +{ + int len = 0; + int leng,res; + psiconv_u8 temp; + + psiconv_progress(lev+1,off+len,"Going to read a sheet cell reference"); + psiconv_progress(lev+2,off+len,"Going to read the row reference"); + if ((res = psiconv_parse_sheet_ref(buf,lev+2,off+len,&leng,&result->row))) + goto ERROR; + len += leng; + psiconv_progress(lev+2,off+len,"Going to read the column reference"); + if ((res = psiconv_parse_sheet_ref(buf,lev+2,off+len,&leng,&result->column))) + goto ERROR; + len += leng; + + psiconv_progress(lev+2,off+len, + "Going to read the trailing byte (%02x expected)",0); + temp = psiconv_read_u8(buf,lev+2,off+len,&res); + if (res) + goto ERROR; + if (temp != 0) { + psiconv_warn(lev+2,off+len,"Unknown byte in cell reference (ignored"); + psiconv_debug(lev+2,off+len,"Trailing byte: %02x",temp); + } + len ++; + psiconv_progress(lev,off+len-1, + "End of cell reference (total length: %08x)", len); + if (length) + *length = len; + return 0; +ERROR: + if (length) + *length = 0; + return res; +} + +static int psiconv_parse_sheet_cell_block(const psiconv_buffer buf,int lev, + psiconv_u32 off, int *length, + psiconv_sheet_cell_block_t *result) +{ + int len = 0; + int leng,res; + + psiconv_progress(lev+1,off+len,"Going to read a sheet cell block"); + psiconv_progress(lev+2,off+len,"Going to read the first cell"); + if ((res = psiconv_parse_sheet_cell_reference(buf,lev+2,off+len,&leng, + &result->first))) + goto ERROR; + len += leng; + psiconv_progress(lev+2,off+len,"Going to read the last cell"); + if ((res = psiconv_parse_sheet_cell_reference(buf,lev+2,off+len,&leng, + &result->last))) + goto ERROR; + len += leng; + psiconv_progress(lev,off+len-1, + "End of cell block (total length: %08x)", len); + if (length) + *length = len; + return 0; +ERROR: + if (length) + *length = 0; + return res; +} + +static int psiconv_parse_formula_element_list(const psiconv_buffer buf, int lev, + psiconv_u32 off, int *length, + psiconv_formula *result, + psiconv_u32 maxlen) { int res=0; int len=0; int leng; int eof = 0; psiconv_u8 marker; - psiconv_u32 bytelen; psiconv_formula_list formula_stack; psiconv_formula formula,subformula1,subformula2,subformula3,subformula4; - psiconv_progress(lev+1,off,"Going to read a formula"); + psiconv_progress(lev+1,off,"Going to read a formula element list"); if (!(*result = malloc(sizeof(**result)))) goto ERROR1; if (!(formula_stack = psiconv_list_new(sizeof(struct psiconv_formula_s)))) @@ -326,17 +475,7 @@ goto ERROR7; subformula4->type = psiconv_formula_unknown; - psiconv_progress(lev+2,off+len, - "Going to read the formula byte length"); - bytelen = psiconv_read_S(buf,lev+2,off+len,&leng,&res); - if (res) - goto ERROR8; - psiconv_debug(lev+2,off+len,"Formula byte length: %d",bytelen); - len += leng; - bytelen += len; - - psiconv_progress(lev+2,off+len,"Going to read the formula items"); - while (!eof && len < bytelen) { + while (!eof && len+off < maxlen) { psiconv_progress(lev+3,off+len,"Going to read a formula item marker"); marker = psiconv_read_u8(buf,lev+2,off+len,&res); if (res) @@ -348,9 +487,14 @@ if (formula_elements[marker].formula_type == psiconv_formula_unknown) { psiconv_warn(lev+3,off+len,"Unknown formula marker found!"); goto ERROR8; - } else if (formula_elements[marker].formula_type == - psiconv_formula_mark_eof) { - psiconv_progress(lev+3,off+len,"End of formula"); + } else if ((formula_elements[marker].formula_type == + psiconv_formula_mark_eof) || + (formula_elements[marker].formula_type == + psiconv_formula_mark_opend) || + (formula_elements[marker].formula_type == + psiconv_formula_mark_opsep)) { + len--; + psiconv_progress(lev+3,off+len,"End of this formula list"); eof = 1; } else if (formula_elements[marker].formula_type == psiconv_formula_dat_int) { @@ -377,21 +521,44 @@ if ((res = psiconv_list_add(formula_stack,formula))) goto ERROR8; formula->type = psiconv_formula_unknown; - + } else if (formula_elements[marker].formula_type == + psiconv_formula_dat_cellref) { + psiconv_progress(lev+3,off+len,"Next item: a cell reference"); + if ((res = psiconv_parse_sheet_cell_reference(buf,lev+2,off+len,&leng, + &formula->data.dat_cellref))) + goto ERROR8; + formula->type = formula_elements[marker].formula_type; + len += leng; + if ((res = psiconv_list_add(formula_stack,formula))) + goto ERROR8; + formula->type = psiconv_formula_unknown; + } else if (formula_elements[marker].formula_type == + psiconv_formula_dat_cellblock) { + psiconv_progress(lev+3,off+len,"Next item: a cell block"); + if ((res = psiconv_parse_sheet_cell_block(buf,lev+2,off+len,&leng, + &formula->data.dat_cellblock))) + goto ERROR8; + formula->type = formula_elements[marker].formula_type; + len += leng; + if ((res = psiconv_list_add(formula_stack,formula))) + goto ERROR8; + formula->type = psiconv_formula_unknown; + } else if (formula_elements[marker].formula_type == + psiconv_formula_dat_string) { + psiconv_progress(lev+3,off+len,"Next item: a string"); + formula->data.dat_string = + psiconv_read_sheet_string(buf,lev+2,off+len,&leng,&res); + if (res) + goto ERROR8; + formula->type = formula_elements[marker].formula_type; + len += leng; + if ((res = psiconv_list_add(formula_stack,formula))) + goto ERROR8; + formula->type = psiconv_formula_unknown; } else if ((formula_elements[marker].formula_type == psiconv_formula_dat_var) || (formula_elements[marker].formula_type == - psiconv_formula_dat_string) || - (formula_elements[marker].formula_type == - psiconv_formula_dat_cellref) || - (formula_elements[marker].formula_type == - psiconv_formula_dat_cellblock) || - (formula_elements[marker].formula_type == - psiconv_formula_dat_vcellblock) || - (formula_elements[marker].formula_type == - psiconv_formula_mark_opsep) || - (formula_elements[marker].formula_type == - psiconv_formula_mark_opend)) { + psiconv_formula_dat_vcellblock)) { psiconv_warn(lev+3,off+len,"Not yet supported formula mark!"); goto ERROR8; } else if (formula_elements[marker].number_of_args == -1) { @@ -432,10 +599,10 @@ subformula1->type = formula->type = psiconv_formula_unknown; } } - if ((len != bytelen) || !eof) { + if ((len+off > maxlen) || !eof) { psiconv_warn(lev+2,off+len,"Formula corrupted!"); psiconv_debug(lev+2,off+len,"Expected end: %04x, found end: %04x", - bytelen,len); + maxlen,len+off); goto ERROR8; } if ((psiconv_list_length(formula_stack)) != 1) { @@ -453,7 +620,7 @@ *length = len; psiconv_progress(lev,off+len-1, - "End of formula (total length: %08x)", len); + "End of formula element list (total length: %08x)", len); return 0; ERROR8: @@ -471,6 +638,75 @@ ERROR2: free (*result); ERROR1: + psiconv_warn(lev+1,off,"Reading of formula element list failed"); + if (length) + *length = 0; + if (!res) + return -PSICONV_E_NOMEM; + else + return res; +} + + + + +int psiconv_parse_formula(const psiconv_buffer buf, int lev, + psiconv_u32 off, int *length, + psiconv_formula *result) +{ + int res=0; + int len=0; + int leng; + psiconv_u32 bytelen,formula_end; + psiconv_u8 temp; + + psiconv_progress(lev+1,off,"Going to read a formula"); + + psiconv_progress(lev+2,off+len, + "Going to read the formula byte length"); + bytelen = psiconv_read_S(buf,lev+2,off+len,&leng,&res); + if (res) + goto ERROR1; + psiconv_debug(lev+2,off+len,"Formula byte length: %d",bytelen); + len += leng; + bytelen += len; + formula_end = off + bytelen; + + psiconv_progress(lev+2,off+len,"Going to read the formula elements list"); + if ((res = psiconv_parse_formula_element_list(buf,lev+2,off+len,&leng, + result,formula_end))) + goto ERROR1; + len += leng; + + psiconv_progress(lev+2,off+len,"Going to read the eof marker"); + temp = psiconv_read_u8(buf,lev+2,off+len,&res); + if (res) + goto ERROR2; + if (formula_elements[temp].formula_type != psiconv_formula_mark_eof) { + psiconv_warn(lev+2,off+len,"Formula corrupted!"); + psiconv_debug(lev+2,off+len,"Expected marker: %02x, found byte: %02x", + 0x15,temp); + goto ERROR2; + } + len ++; + + if (off+len != formula_end) { + psiconv_warn(lev+2,off+len,"Formula corrupted!"); + psiconv_debug(lev+2,off+len,"Expected end: %04x, found end: %04x", + formula_end,len+off); + goto ERROR2; + } + + if (length) + *length = len; + + psiconv_progress(lev,off+len-1, + "End of formula (total length: %08x)", len); + return 0; + +ERROR2: + psiconv_free_formula(*result); +ERROR1: psiconv_warn(lev+1,off,"Reading of formula failed"); if (length) *length = 0; @@ -480,3 +716,4 @@ return res; } +