Coverage Report

Created: 2026-10-17 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libxls/src/xls.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 *
3
 * Copyright 2004 Komarov Valery
4
 * Copyright 2006 Christophe Leitienne
5
 * Copyright 2008-2017 David Hoerl
6
 * Copyright 2013 Bob Colbert
7
 * Copyright 2013-2018 Evan Miller
8
 *
9
 * This file is part of libxls -- A multiplatform, C/C++ library for parsing
10
 * Excel(TM) files.
11
 *
12
 * Redistribution and use in source and binary forms, with or without
13
 * modification, are permitted provided that the following conditions are met:
14
 *
15
 *    1. Redistributions of source code must retain the above copyright notice,
16
 *    this list of conditions and the following disclaimer.
17
 *
18
 *    2. Redistributions in binary form must reproduce the above copyright
19
 *    notice, this list of conditions and the following disclaimer in the
20
 *    documentation and/or other materials provided with the distribution.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS
23
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
26
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
 *
34
 */
35
36
#include "config.h"
37
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <stddef.h>
41
#include <errno.h>
42
43
#ifdef HAVE_ICONV
44
#include <iconv.h>
45
#endif
46
47
#include <memory.h>
48
#include <sys/types.h>
49
#include <string.h>
50
#include <wchar.h>
51
52
#include "../include/libxls/endian.h"
53
#include "../include/libxls/locale.h"
54
#include "../include/xls.h"
55
56
#ifndef min
57
7.57k
#define min(a,b) ((a) < (b) ? (a) : (b))
58
#endif
59
60
//#define DEBUG_DRAWINGS
61
int xls_debug = 0;
62
63
static double NumFromRk(DWORD drk);
64
static xls_formula_handler formula_handler;
65
66
static xls_error_t xls_addSST(xlsWorkBook* pWB, SST* sst, DWORD size);
67
static xls_error_t xls_appendSST(xlsWorkBook* pWB, BYTE* buf, DWORD size);
68
static xls_error_t xls_addFormat(xlsWorkBook* pWB, FORMAT* format, DWORD size);
69
static xls_error_t xls_addSheet(xlsWorkBook* pWB, BOUNDSHEET* bs, DWORD size);
70
static xls_error_t xls_addRow(xlsWorkSheet* pWS,ROW* row);
71
static xls_error_t xls_makeTable(xlsWorkSheet* pWS);
72
static struct st_cell_data *xls_addCell(xlsWorkSheet* pWS, BOF* bof, BYTE* buf);
73
static char *xls_addFont(xlsWorkBook* pWB, FONT* font, DWORD size);
74
static xls_error_t xls_addXF8(xlsWorkBook* pWB, XF8* xf);
75
static xls_error_t xls_addXF5(xlsWorkBook* pWB, XF5* xf);
76
static xls_error_t xls_addColinfo(xlsWorkSheet* pWS, COLINFO* colinfo);
77
static xls_error_t xls_mergedCells(xlsWorkSheet* pWS, BOF* bof, BYTE* buf);
78
static xls_error_t xls_preparseWorkSheet(xlsWorkSheet* pWS);
79
static xls_error_t xls_formatColumn(xlsWorkSheet* pWS);
80
static void xls_dumpSummary(char *buf, size_t size, int isSummary, xlsSummaryInfo *pSI);
81
static xls_error_t xls_readSummaryStream(xlsWorkBook *pWB, OLE2 *ole, const char *name, char **out, size_t *out_len);
82
83
#if defined(_AIX) || defined(__sun)
84
#pragma pack(1)
85
#else
86
#pragma pack(push, 1)
87
#endif
88
89
typedef struct {
90
  uint32_t    format[4];
91
  uint32_t    offset;
92
} sectionList;
93
94
typedef struct {
95
  uint16_t    sig;
96
  uint16_t    _empty;
97
  uint32_t    os;
98
  uint32_t    format[4];
99
  uint32_t    count;
100
  sectionList   secList[];
101
} header;
102
103
typedef struct {
104
  uint32_t    propertyID;
105
  uint32_t    sectionOffset;
106
} propertyList;
107
108
typedef struct {
109
  uint32_t    length;
110
  uint32_t    numProperties;
111
  propertyList  properties[];
112
} sectionHeader;
113
114
typedef struct {
115
  uint32_t    propertyID;
116
  uint32_t    data[];
117
} property;
118
119
#pragma pack(pop)
120
121
int xls(int debug)
122
0
{
123
0
  xls_debug = debug;
124
0
    return 1;
125
0
}
126
127
static xls_error_t xls_addSST(xlsWorkBook* pWB,SST* sst,DWORD size)
128
375
{
129
375
    verbose("xls_addSST");
130
131
375
    pWB->sst.continued=0;
132
375
    pWB->sst.lastln=0;
133
375
    pWB->sst.lastid=0;
134
375
    pWB->sst.lastrt=0;
135
375
    pWB->sst.lastsz=0;
136
137
375
    if (sst->num > (1<<26)) // 64 MB
138
10
        return LIBXLS_ERROR_MALLOC;
139
140
365
    if (pWB->sst.string)
141
6
        return LIBXLS_ERROR_PARSE;
142
143
359
    if ((pWB->sst.string = calloc(sst->num,
144
359
                    sizeof(struct str_sst_string))) == NULL) {
145
0
        pWB->sst.count = 0;
146
0
        return LIBXLS_ERROR_MALLOC;
147
0
    }
148
359
    pWB->sst.count = sst->num;
149
150
359
    return xls_appendSST(pWB, sst->strings, size - offsetof(SST, strings));
151
359
}
152
153
static xls_error_t xls_appendSST(xlsWorkBook* pWB, BYTE* buf, DWORD size)
154
2.73k
{
155
2.73k
    DWORD ln; // String character count
156
2.73k
    DWORD ofs;  // Current offset in SST buffer
157
2.73k
    DWORD rt; // Count of rich text formatting runs
158
2.73k
    DWORD sz; // Size of asian phonetic settings block
159
2.73k
    BYTE flag;  // String flags
160
2.73k
    char* ret = NULL;
161
162
2.73k
    if (xls_debug) {
163
0
      printf("xls_appendSST %u\n", size);
164
0
    }
165
166
2.73k
  sz = rt = ln = 0; // kch
167
2.73k
    ofs=0;
168
169
13.9k
  while(ofs<size)
170
11.2k
    {
171
11.2k
        int ln_toread;
172
173
        // Restore state when we're in a continue record
174
        // or read string length
175
11.2k
        if (pWB->sst.continued) {
176
2.12k
            ln=pWB->sst.lastln;
177
2.12k
            rt=pWB->sst.lastrt;
178
2.12k
            sz=pWB->sst.lastsz;
179
9.09k
        } else {
180
9.09k
            if (ofs + 2 > size) {
181
18
                return LIBXLS_ERROR_PARSE;
182
18
            }
183
9.07k
            ln = buf[ofs+0] + (buf[ofs+1] << 8);
184
9.07k
            rt = 0;
185
9.07k
            sz = 0;
186
187
9.07k
            ofs+=2;
188
9.07k
        }
189
190
11.1k
    if (xls_debug) {
191
0
          printf("ln=%u\n", ln);
192
0
    }
193
194
        // Read flags
195
11.1k
        if ( !pWB->sst.continued || (pWB->sst.continued && ln != 0) ) {
196
10.5k
            if (ofs + sizeof(BYTE) > size) {
197
4
                return LIBXLS_ERROR_PARSE;
198
4
            }
199
10.5k
            flag=*(BYTE *)(buf+ofs);
200
10.5k
            ofs++;
201
202
            // Count of rich text formatting runs
203
10.5k
            if (flag & 0x8) {
204
1.71k
                if (ofs + sizeof(WORD) > size) {
205
4
                    return LIBXLS_ERROR_PARSE;
206
4
                }
207
1.71k
                rt = buf[ofs+0] + (buf[ofs+1] << 8);
208
1.71k
                ofs+=2;
209
1.71k
            }
210
211
            // Size of asian phonetic settings block
212
10.5k
            if (flag & 0x4) {
213
1.89k
                if (ofs + sizeof(DWORD) > size) {
214
4
                    return LIBXLS_ERROR_PARSE;
215
4
                }
216
1.88k
                sz = buf[ofs+0] + (buf[ofs+1] << 8) + (buf[ofs+2] << 16) + ((DWORD)buf[ofs+3] << 24);
217
1.88k
                ofs+=4;
218
219
1.88k
        if (xls_debug) {
220
0
          printf("sz=%u\n", sz);
221
0
        }
222
1.88k
            }
223
10.5k
        } else {
224
642
            flag = 0;
225
642
        }
226
227
    // Read characters (compressed or not)
228
11.1k
        ln_toread = 0;
229
11.1k
        if (ln > 0) {
230
4.71k
            if (flag & 0x1) {
231
1.80k
                size_t new_len = 0;
232
1.80k
                ln_toread = min((size-ofs)/2, ln);
233
1.80k
                ret=unicode_decode((char *)buf+ofs, ln_toread*2, pWB);
234
235
1.80k
                if (ret == NULL) {
236
618
                    ret = strdup("*failed to decode utf16*");
237
618
                }
238
239
1.80k
                ln -= ln_toread;
240
1.80k
                ofs+=ln_toread*2;
241
242
1.80k
                if (xls_debug) {
243
0
                    new_len = strlen(ret);
244
0
                  printf("String16SST: %s(%lu)\n", ret, (unsigned long)new_len);
245
0
                }
246
2.90k
            } else {
247
2.90k
                ln_toread = min((size-ofs), ln);
248
249
2.90k
                ret = codepage_decode((char *)buf+ofs, ln_toread, pWB);
250
2.90k
                if (ret == NULL) {
251
14
                    ret = strdup("*failed to decode BIFF5 string*");
252
14
                }
253
254
2.90k
                ln  -= ln_toread;
255
2.90k
                ofs += ln_toread;
256
257
2.90k
                if (xls_debug) {
258
0
                  printf("String8SST: %s(%u) \n",ret,ln);
259
0
                }
260
2.90k
            }
261
6.46k
        } else {
262
6.46k
            ret = strdup("");
263
6.46k
        }
264
265
11.1k
        if (ln_toread > 0 || !pWB->sst.continued) {
266
            // Concat string if it's a continue, or add string in table
267
9.79k
            if (!pWB->sst.continued) {
268
9.06k
                if (pWB->sst.lastid >= pWB->sst.count) {
269
7
                    free(ret);
270
7
                    return LIBXLS_ERROR_PARSE;
271
7
                }
272
9.05k
                pWB->sst.lastid++;
273
9.05k
                pWB->sst.string[pWB->sst.lastid-1].str=ret;
274
9.05k
            } else {
275
732
                char *tmp = pWB->sst.string[pWB->sst.lastid-1].str;
276
732
                if (tmp == NULL) {
277
0
                    free(ret);
278
0
                    return LIBXLS_ERROR_PARSE;
279
0
                }
280
732
                tmp = realloc(tmp, strlen(tmp)+strlen(ret)+1);
281
732
                if (tmp == NULL)  {
282
0
                    free(ret);
283
0
                    return LIBXLS_ERROR_MALLOC;
284
0
                }
285
732
                pWB->sst.string[pWB->sst.lastid-1].str=tmp;
286
732
                memcpy(tmp+strlen(tmp), ret, strlen(ret)+1);
287
732
        free(ret);
288
732
            }
289
290
9.78k
      if (xls_debug) {
291
0
              printf("String %4u: %s<end>\n", pWB->sst.lastid-1, pWB->sst.string[pWB->sst.lastid-1].str);
292
0
      }
293
9.78k
        } else {
294
1.38k
            free(ret);
295
1.38k
  }
296
297
    // Jump list of rich text formatting runs
298
11.1k
        if (ofs < size && rt > 0) {
299
1.18k
            int rt_toread = min((size-ofs)/4, rt);
300
1.18k
            rt -= rt_toread;
301
1.18k
            ofs += rt_toread*4;
302
1.18k
        }
303
304
    // Jump asian phonetic settings block
305
11.1k
        if (ofs < size && sz > 0) {
306
1.67k
            int sz_toread = min((size-ofs), sz);
307
1.67k
            sz -= sz_toread;
308
1.67k
            ofs += sz_toread;
309
1.67k
        }
310
311
11.1k
        pWB->sst.continued=0;
312
11.1k
    }
313
314
    // Save current character count and count of rich text formatting runs and size of asian phonetic settings block
315
2.69k
  if (ln > 0 || rt > 0 || sz > 0) {
316
2.43k
    pWB->sst.continued = 1;
317
2.43k
    pWB->sst.lastln = ln;
318
2.43k
    pWB->sst.lastrt = rt;
319
2.43k
    pWB->sst.lastsz = sz;
320
321
2.43k
    if (xls_debug) {
322
0
      printf("continued: ln=%u, rt=%u, sz=%u\n", ln, rt, sz);
323
0
    }
324
2.43k
  }
325
326
2.69k
    return LIBXLS_OK;
327
2.73k
}
328
329
static double NumFromRk(DWORD drk)
330
24.0k
{
331
24.0k
  double ret;
332
333
  // What kind of value is this ?
334
24.0k
    if (drk & 0x02) {
335
      // Integer value
336
5.98k
    int tmp = (int)drk >> 2;  // cast to keep it negative in < 0
337
5.98k
        ret = (double)tmp;
338
18.0k
    } else {
339
      // Floating point value;
340
18.0k
    unsigned64_t tmp = drk & 0xfffffffc;
341
18.0k
    tmp <<= 32;
342
18.0k
    memcpy(&ret, &tmp, sizeof(unsigned64_t));
343
18.0k
    }
344
    // Is value multiplied by 100 ?
345
24.0k
    if (drk & 0x01) {
346
6.79k
        ret /= 100.0;
347
6.79k
    }
348
24.0k
    return ret;
349
24.0k
}
350
351
static xls_error_t xls_addSheet(xlsWorkBook* pWB, BOUNDSHEET *bs, DWORD size)
352
27.1k
{
353
27.1k
  char * name;
354
27.1k
  DWORD filepos;
355
27.1k
  BYTE visible, type;
356
357
27.1k
  filepos = bs->filepos;
358
27.1k
  visible = bs->visible;
359
27.1k
  type = bs->type;
360
361
  // printf("charset=%s uni=%d\n", pWB->charset, unicode);
362
  // printf("bs name %.*s\n", bs->name[0], bs->name+1);
363
27.1k
  name = get_string(bs->name, size - offsetof(BOUNDSHEET, name), 0, pWB);
364
  // printf("name=%s\n", name);
365
366
27.1k
  if(xls_debug) {
367
0
    printf ("xls_addSheet[0x%x]\n", type);
368
0
    switch (type & 0x0f)
369
0
    {
370
0
    case 0x00:
371
      /* worksheet or dialog sheet */
372
0
      printf ("85: Worksheet or dialog sheet\n");
373
0
      break;
374
0
    case 0x01:
375
      /* Microsoft Excel 4.0 macro sheet */
376
0
      printf ("85: Microsoft Excel 4.0 macro sheet\n");
377
0
      break;
378
0
    case 0x02:
379
      /* Chart */
380
0
      printf ("85: Chart sheet\n");
381
0
      break;
382
0
    case 0x06:
383
      /* Visual Basic module */
384
0
      printf ("85: Visual Basic sheet\n");
385
0
      break;
386
0
    default:
387
0
      printf ("???\n");
388
0
      break;
389
0
    }
390
0
    printf("visible: %x\n", visible);
391
0
    printf("    Pos: %Xh\n",filepos);
392
0
    printf("   type: %.4Xh\n",type);
393
0
    printf("   name: %s\n", name);
394
0
  }
395
396
27.1k
    struct st_sheet_data *new_sheets = realloc(pWB->sheets.sheet,(pWB->sheets.count+1)*sizeof (struct st_sheet_data));
397
27.1k
    if (new_sheets == NULL) {
398
0
        free(name);
399
0
        return LIBXLS_ERROR_MALLOC;
400
0
    }
401
27.1k
    pWB->sheets.sheet = new_sheets;
402
403
27.1k
    pWB->sheets.sheet[pWB->sheets.count].name=name;
404
27.1k
    pWB->sheets.sheet[pWB->sheets.count].filepos=filepos;
405
27.1k
    pWB->sheets.sheet[pWB->sheets.count].visibility=visible;
406
27.1k
    pWB->sheets.sheet[pWB->sheets.count].type=type;
407
27.1k
    pWB->sheets.count++;
408
409
27.1k
  return LIBXLS_OK;
410
27.1k
}
411
412
413
static xls_error_t xls_addRow(xlsWorkSheet* pWS,ROW* row)
414
956
{
415
956
    struct st_row_data* tmp;
416
417
    //verbose ("xls_addRow");
418
419
956
    if (row->index > pWS->rows.lastrow)
420
0
        return LIBXLS_ERROR_PARSE;
421
422
956
    tmp=&pWS->rows.row[row->index];
423
956
    tmp->height=row->height;
424
956
    tmp->fcell=row->fcell;
425
956
    tmp->lcell=row->lcell;
426
956
    tmp->flags=row->flags;
427
956
    tmp->xf=row->xf&0xfff;
428
956
    tmp->xfflags=(row->xf >> 8)&0xf0;
429
956
    if(xls_debug) xls_showROW(tmp);
430
431
956
    return LIBXLS_OK;
432
956
}
433
434
static xls_error_t xls_makeTable(xlsWorkSheet* pWS)
435
8.43k
{
436
8.43k
    DWORD i,t;
437
8.43k
    struct st_row_data* tmp;
438
8.43k
    verbose ("xls_makeTable");
439
440
8.43k
    if ((pWS->rows.row = calloc((pWS->rows.lastrow+1),sizeof(struct st_row_data))) == NULL)
441
0
        return LIBXLS_ERROR_MALLOC;
442
443
  // printf("ALLOC: rows=%d cols=%d\n", pWS->rows.lastrow, pWS->rows.lastcol);
444
86.0M
    for (t=0;t<=pWS->rows.lastrow;t++)
445
86.0M
    {
446
86.0M
        tmp=&pWS->rows.row[t];
447
86.0M
        tmp->index=t;
448
86.0M
        tmp->fcell=0;
449
86.0M
        tmp->lcell=pWS->rows.lastcol;
450
451
86.0M
    tmp->cells.count = pWS->rows.lastcol+1;
452
86.0M
        if ((tmp->cells.cell = calloc(tmp->cells.count, sizeof(struct st_cell_data))) == NULL) {
453
0
            tmp->cells.count = 0;
454
0
            return LIBXLS_ERROR_MALLOC;
455
0
        }
456
457
5.07G
        for (i=0;i<=pWS->rows.lastcol;i++)
458
4.98G
        {
459
4.98G
            tmp->cells.cell[i].col = i;
460
4.98G
            tmp->cells.cell[i].row = t;
461
4.98G
            tmp->cells.cell[i].width = pWS->defcolwidth;
462
4.98G
            tmp->cells.cell[i].id = XLS_RECORD_BLANK;
463
4.98G
        }
464
86.0M
    }
465
8.43k
    return LIBXLS_OK;
466
8.43k
}
467
468
61.1k
int xls_isCellTooSmall(xlsWorkBook* pWB, BOF* bof, BYTE* buf) {
469
61.1k
    if (bof->size < sizeof(COL))
470
1.12k
        return 1;
471
472
59.9k
    if (bof->id == XLS_RECORD_FORMULA || bof->id == XLS_RECORD_FORMULA_ALT)
473
12.1k
        return (bof->size < offsetof(FORMULA, value));
474
475
47.8k
    if (bof->id == XLS_RECORD_MULRK)
476
6.97k
        return (bof->size < offsetof(MULRK, rk));
477
478
40.9k
    if (bof->id == XLS_RECORD_MULBLANK)
479
6.74k
        return (bof->size < offsetof(MULBLANK, xf));
480
481
34.1k
    if (bof->id == XLS_RECORD_LABELSST)
482
8.59k
        return (bof->size < offsetof(LABEL, value) + (pWB->is5ver ? 2 : 4));
483
484
25.5k
    if (bof->id == XLS_RECORD_LABEL || bof->id == XLS_RECORD_RSTRING) {
485
7.40k
        if (bof->size < offsetof(LABEL, value) + 2)
486
204
            return 1;
487
488
7.20k
        size_t label_len = ((LABEL*)buf)->value[0] + (((LABEL*)buf)->value[1] << 8);
489
7.20k
        if (pWB->is5ver) {
490
812
            return (bof->size < offsetof(LABEL, value) + 2 + label_len);
491
812
        }
492
493
6.38k
        if (bof->size < offsetof(LABEL, value) + 3)
494
198
            return 1;
495
496
6.19k
        if ((((LABEL*)buf)->value[2] & 0x01) == 0) {
497
2.08k
            return (bof->size < offsetof(LABEL, value) + 3 + label_len);
498
2.08k
        }
499
4.10k
        return (bof->size < offsetof(LABEL, value) + 3 + 2 * label_len);
500
6.19k
    }
501
502
18.1k
    if (bof->id == XLS_RECORD_RK)
503
5.47k
        return (bof->size < sizeof(RK));
504
505
12.6k
    if (bof->id == XLS_RECORD_NUMBER)
506
3.69k
        return (bof->size < sizeof(BR_NUMBER));
507
508
8.98k
    if (bof->id == XLS_RECORD_BOOLERR)
509
5.94k
        return (bof->size < sizeof(BOOLERR));
510
511
3.03k
    return 0;
512
8.98k
}
513
514
51.9k
void xls_cell_set_str(struct st_cell_data *cell, char *str) {
515
51.9k
    if (cell->str) {
516
13.2k
        free(cell->str);
517
13.2k
    }
518
51.9k
    cell->str = str;
519
51.9k
}
520
521
static struct st_cell_data *xls_addCell(xlsWorkSheet* pWS,BOF* bof,BYTE* buf)
522
27.0k
{
523
27.0k
    struct st_cell_data*  cell;
524
27.0k
    struct st_row_data*   row;
525
27.0k
    WORD                    col;
526
27.0k
    int           i;
527
528
27.0k
  verbose ("xls_addCell");
529
530
27.0k
    if (xls_isCellTooSmall(pWS->workbook, bof, buf))
531
0
        return NULL;
532
533
  // printf("ROW: %u COL: %u\n", xlsShortVal(((COL*)buf)->row), xlsShortVal(((COL*)buf)->col));
534
27.0k
    row=&pWS->rows.row[xlsShortVal(((COL*)buf)->row)];
535
536
27.0k
    col = xlsShortVal(((COL*)buf)->col);
537
27.0k
    if (col >= row->cells.count) {
538
494
        if (xls_debug) fprintf(stderr, "Error: Column index out of bounds\n");
539
494
        return NULL;
540
494
    }
541
26.6k
    cell = &row->cells.cell[col];
542
543
26.6k
    cell->id=bof->id;
544
26.6k
    cell->xf=xlsShortVal(((COL*)buf)->xf);
545
546
26.6k
    switch (bof->id)
547
26.6k
    {
548
2.45k
    case XLS_RECORD_FORMULA:
549
5.96k
    case XLS_RECORD_FORMULA_ALT:
550
5.96k
    xlsConvertFormula((FORMULA *)buf);
551
5.96k
        cell->id=XLS_RECORD_FORMULA;
552
5.96k
        if (((FORMULA*)buf)->res!=0xffff) {
553
      // if a double, then set double and clear l
554
3.38k
      cell->l=0;
555
3.38k
      memcpy(&cell->d, &((FORMULA*)buf)->resid, sizeof(double));  // Required for ARM
556
3.38k
            cell->id = XLS_RECORD_NUMBER; // hack
557
3.38k
            xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
558
3.38k
            cell->id = bof->id;
559
3.38k
    } else {
560
2.58k
      double d = ((FORMULA*)buf)->resdata[1];
561
2.58k
      cell->l = 0xFFFF;
562
2.58k
      switch(((FORMULA*)buf)->resid) {
563
52
      case 0:   // String
564
52
        break; // cell is half complete, get the STRING next record
565
737
      case 1:   // Boolean
566
737
        memcpy(&cell->d, &d, sizeof(double)); // Required for ARM
567
737
                xls_cell_set_str(cell, strdup("bool"));
568
737
        break;
569
589
      case 2:   // error
570
589
        memcpy(&cell->d, &d, sizeof(double)); // Required for ARM
571
589
                xls_cell_set_str(cell, strdup("error"));
572
589
        break;
573
557
      case 3:   // empty string
574
557
                xls_cell_set_str(cell, strdup(""));
575
557
        break;
576
2.58k
      }
577
2.58k
    }
578
5.96k
    if(formula_handler) formula_handler(bof->id, bof->size, buf);
579
5.96k
        break;
580
2.76k
    case XLS_RECORD_MULRK:
581
24.1k
        for (i = 0; i < (bof->size - 6)/6; i++)  // 6 == 2 row + 2 col + 2 trailing index
582
21.5k
        {
583
21.5k
            WORD index = col + i;
584
21.5k
            if(index >= row->cells.count) {
585
198
                if (xls_debug) fprintf(stderr, "Error: MULTI-RK index out of bounds\n");
586
198
                return NULL;
587
198
            }
588
21.3k
            cell=&row->cells.cell[index];
589
21.3k
            cell->id=XLS_RECORD_RK;
590
21.3k
            cell->xf=xlsShortVal(((MULRK*)buf)->rk[i].xf);
591
21.3k
            cell->d=NumFromRk(xlsIntVal(((MULRK*)buf)->rk[i].value));
592
21.3k
            xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
593
21.3k
        }
594
2.56k
        break;
595
2.56k
    case XLS_RECORD_MULBLANK:
596
9.25k
        for (i = 0; i < (bof->size - 6)/2; i++)  // 6 == 2 row + 2 col + 2 trailing index
597
7.21k
        {
598
7.21k
            WORD index = col + i;
599
7.21k
            if(index >= row->cells.count) {
600
212
                if (xls_debug) fprintf(stderr, "Error: MULTI-BLANK index out of bounds\n");
601
212
                return NULL;
602
212
            }
603
7.00k
            cell=&row->cells.cell[index];
604
7.00k
            cell->id=XLS_RECORD_BLANK;
605
7.00k
            cell->xf=xlsShortVal(((MULBLANK*)buf)->xf[i]);
606
7.00k
            xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
607
7.00k
        }
608
2.03k
        break;
609
3.92k
    case XLS_RECORD_LABELSST:
610
4.49k
    case XLS_RECORD_LABEL:
611
7.17k
    case XLS_RECORD_RSTRING:
612
7.17k
        xls_cell_set_str(cell, xls_getfcell(pWS->workbook, cell, ((LABEL*)buf)->value));
613
7.17k
        if (cell->str) {
614
2.51k
            sscanf((char *)cell->str, "%d", &cell->l);
615
2.51k
            sscanf((char *)cell->str, "%lf", &cell->d);
616
2.51k
        }
617
7.17k
    break;
618
2.71k
    case XLS_RECORD_RK:
619
2.71k
        cell->d=NumFromRk(xlsIntVal(((RK*)buf)->value));
620
2.71k
        xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
621
2.71k
        break;
622
1.16k
    case XLS_RECORD_BLANK:
623
1.16k
        break;
624
1.76k
    case XLS_RECORD_NUMBER:
625
1.76k
        xlsConvertDouble((BYTE *)&((BR_NUMBER*)buf)->value);
626
1.76k
    memcpy(&cell->d, &((BR_NUMBER*)buf)->value, sizeof(double)); // Required for ARM
627
1.76k
        xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
628
1.76k
        break;
629
2.80k
    case XLS_RECORD_BOOLERR:
630
2.80k
        cell->d = ((BOOLERR *)buf)->value;
631
2.80k
        if (((BOOLERR *)buf)->iserror) {
632
1.24k
            xls_cell_set_str(cell, strdup("error"));
633
1.56k
        } else {
634
1.56k
            xls_cell_set_str(cell, strdup("bool"));
635
1.56k
        }
636
2.80k
        break;
637
0
    default:
638
0
        xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
639
0
        break;
640
26.6k
    }
641
26.1k
    if (xls_debug) xls_showCell(cell);
642
643
26.1k
  return cell;
644
26.6k
}
645
646
static char *xls_addFont(xlsWorkBook* pWB, FONT* font, DWORD size)
647
821
{
648
821
    struct st_font_data* tmp;
649
650
821
    verbose("xls_addFont");
651
652
821
    struct st_font_data *new_fonts = realloc(pWB->fonts.font,(pWB->fonts.count+1)*sizeof(struct st_font_data));
653
821
    if (new_fonts == NULL)
654
0
        return NULL;
655
821
    pWB->fonts.font = new_fonts;
656
657
821
    tmp=&pWB->fonts.font[pWB->fonts.count];
658
659
821
    tmp->name = get_string(font->name, size - offsetof(FONT, name), 0, pWB);
660
661
821
    tmp->height=font->height;
662
821
    tmp->flag=font->flag;
663
821
    tmp->color=font->color;
664
821
    tmp->bold=font->bold;
665
821
    tmp->escapement=font->escapement;
666
821
    tmp->underline=font->underline;
667
821
    tmp->family=font->family;
668
821
    tmp->charset=font->charset;
669
670
    //  xls_showFont(tmp);
671
821
    pWB->fonts.count++;
672
673
821
  return tmp->name;
674
821
}
675
676
static xls_error_t xls_addFormat(xlsWorkBook* pWB, FORMAT* format, DWORD size)
677
448
{
678
448
    struct st_format_data* tmp;
679
680
448
    verbose("xls_addFormat");
681
448
    struct st_format_data *new_formats = realloc(pWB->formats.format, (pWB->formats.count+1)*sizeof(struct st_format_data));
682
448
    if (new_formats == NULL)
683
0
        return LIBXLS_ERROR_MALLOC;
684
448
    pWB->formats.format = new_formats;
685
686
448
    tmp = &pWB->formats.format[pWB->formats.count];
687
448
    tmp->index = format->index;
688
448
    tmp->value = get_string(format->value, size - offsetof(FORMAT, value), (BYTE)!pWB->is5ver, pWB);
689
448
    if(xls_debug) xls_showFormat(tmp);
690
448
    pWB->formats.count++;
691
692
448
    return LIBXLS_OK;
693
448
}
694
695
static xls_error_t xls_addXF8(xlsWorkBook* pWB,XF8* xf)
696
399
{
697
399
    struct st_xf_data* tmp;
698
699
399
    verbose("xls_addXF");
700
399
    struct st_xf_data *new_xfs8 = realloc(pWB->xfs.xf, (pWB->xfs.count+1)*sizeof(struct st_xf_data));
701
399
    if (new_xfs8 == NULL)
702
0
        return LIBXLS_ERROR_MALLOC;
703
399
    pWB->xfs.xf = new_xfs8;
704
705
399
    tmp=&pWB->xfs.xf[pWB->xfs.count];
706
707
399
    tmp->font=xf->font;
708
399
    tmp->format=xf->format;
709
399
    tmp->type=xf->type;
710
399
    tmp->align=xf->align;
711
399
    tmp->rotation=xf->rotation;
712
399
    tmp->ident=xf->ident;
713
399
    tmp->usedattr=xf->usedattr;
714
399
    tmp->linestyle=xf->linestyle;
715
399
    tmp->linecolor=xf->linecolor;
716
399
    tmp->groundcolor=xf->groundcolor;
717
718
    //  xls_showXF(tmp);
719
399
    pWB->xfs.count++;
720
721
399
    return LIBXLS_OK;
722
399
}
723
724
static xls_error_t xls_addXF5(xlsWorkBook* pWB,XF5* xf)
725
481
{
726
481
    struct st_xf_data* tmp;
727
728
481
    verbose("xls_addXF");
729
481
    struct st_xf_data *new_xfs5 = realloc(pWB->xfs.xf, (pWB->xfs.count+1)*sizeof(struct st_xf_data));
730
481
    if (new_xfs5 == NULL)
731
0
        return LIBXLS_ERROR_MALLOC;
732
481
    pWB->xfs.xf = new_xfs5;
733
734
481
    tmp=&pWB->xfs.xf[pWB->xfs.count];
735
736
481
    tmp->font=xf->font;
737
481
    tmp->format=xf->format;
738
481
    tmp->type=xf->type;
739
481
    tmp->align=(BYTE)xf->align;
740
/*
741
    tmp->rotation=xf->rotation;
742
    tmp->ident=xf->ident;
743
    tmp->usedattr=xf->usedattr;
744
    tmp->linestyle=xf->linestyle;
745
    tmp->linecolor=xf->linecolor;
746
    tmp->groundcolor=xf->groundcolor;
747
*/
748
749
    //  xls_showXF(tmp);
750
481
    pWB->xfs.count++;
751
481
    return LIBXLS_OK;
752
481
}
753
754
static xls_error_t xls_addColinfo(xlsWorkSheet* pWS,COLINFO* colinfo)
755
1.73k
{
756
1.73k
    struct st_colinfo_data* tmp;
757
758
1.73k
    verbose("xls_addColinfo");
759
1.73k
    struct st_colinfo_data *new_cols = realloc(pWS->colinfo.col,(pWS->colinfo.count+1)*sizeof(struct st_colinfo_data));
760
1.73k
    if (new_cols == NULL)
761
0
        return LIBXLS_ERROR_MALLOC;
762
1.73k
    pWS->colinfo.col = new_cols;
763
764
1.73k
    tmp=&pWS->colinfo.col[pWS->colinfo.count];
765
1.73k
    tmp->first=colinfo->first;
766
1.73k
    tmp->last=colinfo->last;
767
1.73k
    tmp->width=colinfo->width;
768
1.73k
    tmp->xf=colinfo->xf;
769
1.73k
    tmp->flags=colinfo->flags;
770
771
1.73k
    if(xls_debug) xls_showColinfo(tmp);
772
1.73k
    pWS->colinfo.count++;
773
774
1.73k
    return LIBXLS_OK;
775
1.73k
}
776
777
static xls_error_t xls_mergedCells(xlsWorkSheet* pWS,BOF* bof,BYTE* buf)
778
2.73k
{
779
2.73k
    if (bof->size < sizeof(WORD))
780
234
        return LIBXLS_ERROR_PARSE;
781
782
2.49k
    int count = buf[0] + (buf[1] << 8);
783
2.49k
    DWORD limit = sizeof(WORD)+count*sizeof(struct MERGEDCELLS);
784
2.49k
    if(limit > (DWORD)bof->size) {
785
457
        verbose("Merged Cells Count out of range");
786
457
        return LIBXLS_ERROR_PARSE;
787
457
    }
788
2.04k
    int i,c,r;
789
2.04k
    struct MERGEDCELLS *span;
790
2.04k
    verbose("Merged Cells");
791
4.40k
    for (i=0;i<count;i++)
792
3.32k
    {
793
3.32k
        span=(struct MERGEDCELLS*)(buf+(2+i*sizeof(struct MERGEDCELLS)));
794
3.32k
        xlsConvertMergedcells(span);
795
        //    printf("Merged Cells: [%i,%i] [%i,%i] \n",span->colf,span->rowf,span->coll,span->rowl);
796
        // Sanity check:
797
3.32k
        if(!(   span->rowf <= span->rowl &&
798
3.09k
                span->rowl <= pWS->rows.lastrow &&
799
2.86k
                span->colf <= span->coll &&
800
2.64k
                span->coll <= pWS->rows.lastcol
801
3.32k
        )) {
802
962
            return LIBXLS_ERROR_PARSE;
803
962
        }
804
805
1.54M
        for (r=span->rowf;r<=span->rowl;r++)
806
3.76M
            for (c=span->colf;c<=span->coll;c++)
807
2.22M
                pWS->rows.row[r].cells.cell[c].isHidden=1;
808
2.36k
        pWS->rows.row[span->rowf].cells.cell[span->colf].colspan=(span->coll-span->colf+1);
809
2.36k
        pWS->rows.row[span->rowf].cells.cell[span->colf].rowspan=(span->rowl-span->rowf+1);
810
2.36k
        pWS->rows.row[span->rowf].cells.cell[span->colf].isHidden=0;
811
2.36k
    }
812
1.07k
    return LIBXLS_OK;
813
2.04k
}
814
815
97.8k
int xls_isRecordTooSmall(xlsWorkBook *pWB, BOF *bof1, const BYTE* buf) {
816
97.8k
    switch (bof1->id) {
817
525
        case XLS_RECORD_BOF: // BIFF5-8
818
525
            return (bof1->size < 2 * sizeof(WORD));
819
243
        case XLS_RECORD_CODEPAGE:
820
243
            return (bof1->size < sizeof(WORD));
821
160
    case XLS_RECORD_WINDOW1:
822
160
            return (bof1->size < sizeof(WIND1));
823
376
        case XLS_RECORD_SST:
824
376
            return (bof1->size < offsetof(SST, strings));
825
27.1k
        case XLS_RECORD_BOUNDSHEET:
826
27.1k
            return (bof1->size < offsetof(BOUNDSHEET, name));
827
883
        case XLS_RECORD_XF:
828
883
      if(pWB->is5ver) {
829
481
                return (bof1->size < sizeof(XF5));
830
481
            }
831
402
            return (bof1->size < sizeof(XF8));
832
563
        case XLS_RECORD_FONT:
833
823
        case XLS_RECORD_FONT_ALT:
834
823
            return (bof1->size < offsetof(FONT, name));
835
449
        case XLS_RECORD_FORMAT:
836
449
            return (bof1->size < offsetof(FORMAT, value));
837
906
        case XLS_RECORD_STYLE:
838
906
            {
839
906
                struct {
840
906
                    unsigned short idx;
841
906
                    unsigned char ident;
842
906
                    unsigned char lvl;
843
906
                } *styl;
844
906
                if(bof1->size < 2) {
845
4
                    return 1;
846
4
                }
847
902
                styl = (void *)buf;
848
902
                if(xlsShortVal(styl->idx) & 0x8000) {
849
293
                    return bof1->size < 4;
850
609
                } else {
851
609
                    if(bof1->size < 3) return 1;
852
606
                    return bof1->size < 3 + styl->ident;
853
609
                }
854
902
            }
855
268
    case XLS_RECORD_1904:
856
268
            return (bof1->size < sizeof(BYTE));
857
66.0k
        default:
858
66.0k
            break;
859
97.8k
    }
860
66.0k
    return 0;
861
97.8k
}
862
863
xls_error_t xls_parseWorkBook(xlsWorkBook* pWB)
864
2.00k
{
865
2.00k
    if(!pWB) return LIBXLS_ERROR_NULL_ARGUMENT;
866
867
2.00k
    BOF bof1 = { .id = 0, .size = 0 };
868
2.00k
    BOF bof2 = { .id = 0, .size = 0 };
869
2.00k
    BYTE* buf = NULL;
870
2.00k
  BYTE once = 0;
871
2.00k
    xls_error_t retval = LIBXLS_OK;
872
873
2.00k
    verbose ("xls_parseWorkBook");
874
98.3k
    do {
875
98.3k
    if(xls_debug > 10) {
876
0
      printf("READ WORKBOOK filePos=%ld\n",  (long)pWB->filepos);
877
0
      printf("  OLE: start=%d pos=%u size=%u fatPos=%u\n",
878
0
                    pWB->olestr->start, (unsigned int)pWB->olestr->pos,
879
0
                    (unsigned int)pWB->olestr->size, (unsigned int)pWB->olestr->fatpos); 
880
0
    }
881
882
98.3k
        if (ole2_read(&bof1, 1, 4, pWB->olestr) != 4) {
883
126
            retval = LIBXLS_ERROR_READ;
884
126
            goto cleanup;
885
126
        }
886
98.2k
        xlsConvertBof(&bof1);
887
98.2k
    if(xls_debug) xls_showBOF(&bof1);
888
889
98.2k
        if (bof1.size) {
890
50.2k
            BYTE *new_buf = realloc(buf, bof1.size);
891
50.2k
            if (new_buf == NULL) {
892
0
                if (xls_debug) fprintf(stderr, "Error: failed to allocate buffer of size %d\n", (int)bof1.size);
893
0
                retval = LIBXLS_ERROR_MALLOC;
894
0
                goto cleanup;
895
0
            }
896
50.2k
            buf = new_buf;
897
50.2k
            memset(buf, 0, bof1.size);
898
50.2k
            if (ole2_read(buf, 1, bof1.size, pWB->olestr) != bof1.size) {
899
361
                if (xls_debug) fprintf(stderr, "Error: failed to read OLE block\n");
900
361
                retval = LIBXLS_ERROR_READ;
901
361
                goto  cleanup;
902
361
            }
903
50.2k
        }
904
905
97.8k
        if (xls_isRecordTooSmall(pWB, &bof1, buf)) {
906
42
            retval = LIBXLS_ERROR_PARSE;
907
42
            goto cleanup;
908
42
        }
909
910
97.8k
        switch (bof1.id) {
911
444
        case XLS_RECORD_EOF:
912
            //verbose("EOF");
913
444
            break;
914
525
        case XLS_RECORD_BOF: // BIFF5-8
915
525
            pWB->is5ver = (buf[0] + (buf[1] << 8) != 0x600);
916
525
            pWB->type = buf[2] + (buf[3] << 8);
917
525
            if(xls_debug) {
918
0
                printf("version: %s\n", pWB->is5ver ? "BIFF5" : "BIFF8" );
919
0
                printf("   type: %.2X\n", pWB->type);
920
0
            }
921
525
            break;
922
923
242
        case XLS_RECORD_CODEPAGE:
924
242
            pWB->codepage = buf[0] + (buf[1] << 8);
925
242
      if(xls_debug) printf("codepage: %d\n", pWB->codepage);
926
242
            break;
927
928
2.66k
        case XLS_RECORD_CONTINUE:
929
2.66k
      if(once) {
930
2.65k
        if (bof2.id==XLS_RECORD_SST) {
931
2.37k
          if ((retval = xls_appendSST(pWB,buf,bof1.size)) != LIBXLS_OK)
932
6
                        goto cleanup;
933
2.37k
                }
934
2.65k
        bof1=bof2;
935
2.65k
      }
936
2.65k
            break;
937
938
2.65k
    case XLS_RECORD_WINDOW1:
939
159
      {
940
159
        WIND1 *w = (WIND1*)buf;
941
159
                xlsConvertWindow(w);
942
159
        pWB->activeSheetIdx = w->itabCur;
943
159
        if(xls_debug) {
944
0
          printf("WINDOW1: ");
945
0
          printf("xWn    : %d\n", w->xWn/20);
946
0
          printf("yWn    : %d\n", w->yWn/20);
947
0
          printf("dxWn   : %d\n", w->dxWn/20);
948
0
          printf("dyWn   : %d\n", w->dyWn/20);
949
0
          printf("grbit  : %d\n", w->grbit);
950
0
          printf("itabCur: %d\n", w->itabCur);
951
0
          printf("itabFi : %d\n", w->itabFirst);
952
0
          printf("ctabSel: %d\n", w->ctabSel);
953
0
          printf("wTabRat: %d\n", w->wTabRatio);
954
0
        }
955
159
      }
956
159
      break;
957
958
375
        case XLS_RECORD_SST:
959
      //printf("ADD SST\n");
960
375
            xlsConvertSst((SST *)buf);
961
375
            if ((retval = xls_addSST(pWB,(SST*)buf,bof1.size)) != LIBXLS_OK) {
962
47
                goto cleanup;
963
47
            }
964
328
            break;
965
966
6.53k
        case XLS_RECORD_EXTSST:
967
6.53k
            break;
968
969
27.1k
        case XLS_RECORD_BOUNDSHEET:
970
27.1k
      {
971
        //printf("ADD SHEET\n");
972
27.1k
        BOUNDSHEET *bs = (BOUNDSHEET *)buf;
973
27.1k
                xlsConvertBoundsheet(bs);
974
        // different for BIFF5 and BIFF8
975
27.1k
                if ((retval = xls_addSheet(pWB, bs, bof1.size)) != LIBXLS_OK) {
976
0
                    goto cleanup;
977
0
                }
978
27.1k
      }
979
27.1k
            break;
980
981
27.1k
        case XLS_RECORD_XF:
982
880
      if(pWB->is5ver) {
983
481
        XF5 *xf;
984
481
        xf = (XF5 *)buf;
985
481
                xlsConvertXf5(xf);
986
987
481
        if ((retval = xls_addXF5(pWB,xf)) != LIBXLS_OK) {
988
0
                    goto cleanup;
989
0
                }
990
481
        if(xls_debug) {
991
0
          printf("   font: %d\n", xf->font);
992
0
          printf(" format: %d\n", xf->format);
993
0
          printf("   type: %.4x\n", xf->type);
994
0
          printf("  align: %.4x\n", xf->align);
995
0
          printf("rotatio: %.4x\n", xf->color);
996
0
          printf("  ident: %.4x\n", xf->fill);
997
0
          printf("usedatt: %.4x\n", xf->border);
998
0
          printf("linesty: %.4x\n", xf->linestyle);
999
0
        }
1000
481
      } else {
1001
399
        XF8 *xf;
1002
399
        xf = (XF8 *)buf;
1003
399
                xlsConvertXf8(xf);
1004
1005
399
        if ((retval = xls_addXF8(pWB,xf)) != LIBXLS_OK) {
1006
0
                    goto cleanup;
1007
0
                }
1008
1009
399
        if(xls_debug) {
1010
0
          xls_showXF(xf);
1011
0
        }
1012
399
      }
1013
880
            break;
1014
1015
880
        case XLS_RECORD_FONT:
1016
821
        case XLS_RECORD_FONT_ALT:
1017
821
      {
1018
821
        char *s;
1019
821
        FONT *f = (FONT*)buf;
1020
821
                xlsConvertFont(f);
1021
821
        s = xls_addFont(pWB,f, bof1.size);
1022
821
        if(xls_debug) {
1023
0
          printf(" height: %d\n", f->height);
1024
0
          printf("   flag: 0x%x\n", f->flag);
1025
0
          printf("  color: 0x%x\n", f->color);
1026
0
          printf(" weight: %d\n", f->bold);
1027
0
          printf("escapem: 0x%x\n", f->escapement);
1028
0
          printf("underln: 0x%x\n", f->underline);
1029
0
          printf(" family: 0x%x\n", f->family);
1030
0
          printf("charset: 0x%x\n", f->charset);
1031
0
          if(s) printf("   name: %s\n", s);
1032
0
        }
1033
821
      }
1034
821
      break;
1035
1036
448
        case XLS_RECORD_FORMAT:
1037
448
            xlsConvertFormat((FORMAT *)buf);
1038
448
            if ((retval = xls_addFormat(pWB, (FORMAT*)buf, bof1.size)) != LIBXLS_OK) {
1039
0
                goto cleanup;
1040
0
            }
1041
448
            break;
1042
1043
885
    case XLS_RECORD_STYLE:
1044
885
      if(xls_debug) {
1045
0
        struct { unsigned short idx; unsigned char ident; unsigned char lvl; } *styl;
1046
0
        styl = (void *)buf;
1047
1048
0
        printf("    idx: 0x%x\n", styl->idx & 0x07FF);
1049
0
        if(styl->idx & 0x8000) {
1050
0
          printf("  ident: 0x%x\n", styl->ident);
1051
0
          printf("  level: 0x%x\n", styl->lvl);
1052
0
        } else {
1053
0
          char *s = get_string((char *)&buf[2], bof1.size - 2, 1, pWB);
1054
0
          printf("  name=%s\n", s);
1055
0
                    free(s);
1056
0
        }
1057
0
      }
1058
885
      break;
1059
1060
231
        case XLS_RECORD_PALETTE:
1061
231
      if(xls_debug > 10) {
1062
0
        unsigned char *p = buf + 2;
1063
0
        int idx, len;
1064
1065
0
        len = buf[0] + (buf[1] << 8);
1066
0
        for(idx=0; idx<len; ++idx) {
1067
0
          printf("   Index=0x%2.2x %2.2x%2.2x%2.2x\n", idx+8, p[0], p[1], p[2] );
1068
0
          p += 4;
1069
0
        }
1070
0
      }
1071
231
      break;
1072
1073
256
    case XLS_RECORD_1904:
1074
256
      pWB->is1904 = *(BYTE *)buf; // the field is a short, but with little endian the first byte is 0 or 1
1075
256
      if(xls_debug) {
1076
0
        printf("   mode: 0x%x\n", pWB->is1904);
1077
0
      }
1078
256
      break;
1079
1080
2
    case XLS_RECORD_FILEPASS:
1081
2
      retval = LIBXLS_ERROR_UNSUPPORTED_ENCRYPTION;
1082
2
      goto cleanup;
1083
    
1084
570
    case XLS_RECORD_DEFINEDNAME:
1085
570
      if(xls_debug) {
1086
0
        int i;
1087
0
                printf("   DEFINEDNAME: ");
1088
0
        for(i=0; i<bof1.size; ++i) printf("%2.2x ", buf[i]);
1089
0
        printf("\n");
1090
0
      }
1091
570
      break;
1092
      
1093
55.6k
        default:
1094
55.6k
      if(xls_debug)
1095
0
      {
1096
        //xls_showBOF(&bof1);
1097
0
        printf("    Not Processed in parseWorkBook():  BOF=0x%4.4X size=%d\n", bof1.id, bof1.size);
1098
0
      }
1099
55.6k
            break;
1100
97.8k
        }
1101
97.8k
        bof2=bof1;
1102
97.8k
    once=1;
1103
97.8k
    }
1104
97.8k
    while ((!pWB->olestr->eof)&&(bof1.id!=XLS_RECORD_EOF));
1105
1106
2.00k
cleanup:
1107
2.00k
    if (buf)
1108
1.98k
        free(buf);
1109
1110
2.00k
    return retval;
1111
2.00k
}
1112
1113
1114
static xls_error_t xls_preparseWorkSheet(xlsWorkSheet* pWS)
1115
26.3k
{
1116
26.3k
    if(!pWS) return LIBXLS_ERROR_NULL_ARGUMENT;
1117
1118
26.3k
    BOF tmp;
1119
26.3k
    BYTE* buf = NULL;
1120
26.3k
    xls_error_t retval = LIBXLS_OK;
1121
1122
26.3k
    verbose ("xls_preparseWorkSheet");
1123
1124
26.3k
    if (ole2_seek(pWS->workbook->olestr,pWS->filepos) == -1) {
1125
4.48k
        retval = LIBXLS_ERROR_SEEK;
1126
4.48k
        goto cleanup;
1127
4.48k
    }
1128
21.8k
    do
1129
2.07M
    {
1130
2.07M
    size_t read;
1131
2.07M
    if((read = ole2_read(&tmp, 1, 4, pWS->workbook->olestr)) != 4) {
1132
641
            if (xls_debug) fprintf(stderr, "Error: failed to read OLE size\n");
1133
641
            retval = LIBXLS_ERROR_READ;
1134
641
            goto cleanup;
1135
641
        }
1136
2.07M
        xlsConvertBof(&tmp);
1137
2.07M
        if (tmp.size) {
1138
931k
            BYTE *new_buf = realloc(buf, tmp.size);
1139
931k
            if (new_buf == NULL) {
1140
0
                if (xls_debug) fprintf(stderr, "Error: failed to allocate buffer of size %d\n", (int)tmp.size);
1141
0
                retval = LIBXLS_ERROR_MALLOC;
1142
0
                goto cleanup;
1143
0
            }
1144
931k
            buf = new_buf;
1145
931k
            memset(buf, 0, tmp.size);
1146
931k
            if((read = ole2_read(buf, 1, tmp.size, pWS->workbook->olestr)) != tmp.size) {
1147
8.57k
                if (xls_debug) fprintf(stderr, "Error: failed to read OLE block\n");
1148
8.57k
                retval = LIBXLS_ERROR_READ;
1149
8.57k
                goto cleanup;
1150
8.57k
            }
1151
931k
        }
1152
1153
2.06M
        switch (tmp.id)
1154
2.06M
        {
1155
2.93k
        case XLS_RECORD_DEFCOLWIDTH:
1156
2.93k
            if (tmp.size < sizeof(WORD)) {
1157
210
                retval = LIBXLS_ERROR_PARSE;
1158
210
                goto cleanup;
1159
210
            }
1160
2.72k
            pWS->defcolwidth = (buf[0] << 8) + (buf[1] << 16);
1161
2.72k
            break;
1162
3.15k
        case XLS_RECORD_COLINFO:
1163
3.15k
            if (tmp.size < sizeof(COLINFO)) {
1164
1.42k
                retval = LIBXLS_ERROR_PARSE;
1165
1.42k
                goto cleanup;
1166
1.42k
            }
1167
1.73k
            xlsConvertColinfo((COLINFO*)buf);
1168
1.73k
            if ((retval = xls_addColinfo(pWS,(COLINFO*)buf)) != LIBXLS_OK)
1169
0
                goto cleanup;
1170
1.73k
            break;
1171
1.94k
        case XLS_RECORD_ROW:
1172
1.94k
            if (tmp.size < sizeof(ROW)) {
1173
209
                retval = LIBXLS_ERROR_PARSE;
1174
209
                goto cleanup;
1175
209
            }
1176
1.73k
            xlsConvertRow((ROW*)buf);
1177
            /* The lcell field is 1-indexed whereas lastcol is 0-indexed */
1178
1.73k
            if (pWS->rows.lastcol+1<((ROW*)buf)->lcell)
1179
570
                pWS->rows.lastcol=((ROW*)buf)->lcell-1;
1180
1.73k
            if (pWS->rows.lastrow<((ROW*)buf)->index)
1181
921
                pWS->rows.lastrow=((ROW*)buf)->index;
1182
1.73k
            break;
1183
        /* If the ROW record is incorrect or missing, infer the information from
1184
         * cell data. */
1185
4.24k
        case XLS_RECORD_MULRK:
1186
4.24k
            if (xls_isCellTooSmall(pWS->workbook, &tmp, buf)) {
1187
219
                retval = LIBXLS_ERROR_PARSE;
1188
219
                goto cleanup;
1189
219
            }
1190
4.02k
            if (pWS->rows.lastcol<xlsShortVal(((MULRK*)buf)->col) + (tmp.size - 6)/6 - 1)
1191
1.87k
                pWS->rows.lastcol=xlsShortVal(((MULRK*)buf)->col) + (tmp.size - 6)/6 - 1;
1192
4.02k
            if (pWS->rows.lastrow<xlsShortVal(((MULRK*)buf)->row))
1193
1.60k
                pWS->rows.lastrow=xlsShortVal(((MULRK*)buf)->row);
1194
4.02k
            break;
1195
4.39k
        case XLS_RECORD_MULBLANK:
1196
4.39k
            if (xls_isCellTooSmall(pWS->workbook, &tmp, buf)) {
1197
204
                retval = LIBXLS_ERROR_PARSE;
1198
204
                goto cleanup;
1199
204
            }
1200
4.19k
            if (pWS->rows.lastcol<xlsShortVal(((MULBLANK*)buf)->col) + (tmp.size - 6)/2 - 1)
1201
2.06k
                pWS->rows.lastcol=xlsShortVal(((MULBLANK*)buf)->col) + (tmp.size - 6)/2 - 1;
1202
4.19k
            if (pWS->rows.lastrow<xlsShortVal(((MULBLANK*)buf)->row))
1203
2.14k
                pWS->rows.lastrow=xlsShortVal(((MULBLANK*)buf)->row);
1204
4.19k
            break;
1205
1.94k
        case XLS_RECORD_NUMBER:
1206
4.70k
        case XLS_RECORD_RK:
1207
9.65k
        case XLS_RECORD_LABELSST:
1208
11.5k
        case XLS_RECORD_BLANK:
1209
12.4k
        case XLS_RECORD_LABEL:
1210
15.7k
        case XLS_RECORD_RSTRING:
1211
18.6k
        case XLS_RECORD_FORMULA:
1212
22.2k
        case XLS_RECORD_FORMULA_ALT:
1213
25.3k
        case XLS_RECORD_BOOLERR:
1214
25.3k
            if (xls_isCellTooSmall(pWS->workbook, &tmp, buf)) {
1215
1.39k
                retval = LIBXLS_ERROR_PARSE;
1216
1.39k
                goto cleanup;
1217
1.39k
            }
1218
23.9k
            if (pWS->rows.lastcol<xlsShortVal(((COL*)buf)->col))
1219
4.41k
                pWS->rows.lastcol=xlsShortVal(((COL*)buf)->col);
1220
23.9k
            if (pWS->rows.lastrow<xlsShortVal(((COL*)buf)->row))
1221
5.76k
                pWS->rows.lastrow=xlsShortVal(((COL*)buf)->row);
1222
23.9k
            break;
1223
2.06M
        }
1224
2.05M
        if (pWS->rows.lastcol > 255) {
1225
525
            retval = LIBXLS_ERROR_PARSE;
1226
525
            goto cleanup;
1227
525
        }
1228
2.05M
    }
1229
2.05M
    while ((!pWS->workbook->olestr->eof)&&(tmp.id!=XLS_RECORD_EOF));
1230
1231
26.3k
cleanup:
1232
26.3k
    if (buf)
1233
21.4k
        free(buf);
1234
26.3k
    return retval;
1235
21.8k
}
1236
1237
static xls_error_t xls_formatColumn(xlsWorkSheet* pWS)
1238
8.43k
{
1239
8.43k
    DWORD i,t,ii;
1240
8.43k
    DWORD fcol,lcol;
1241
8.43k
    WORD width;
1242
8.43k
    BYTE isHidden;
1243
1244
10.0k
    for (i=0;i<pWS->colinfo.count;i++)
1245
1.62k
    {
1246
1.62k
        width = pWS->colinfo.col[i].width;
1247
1.62k
        isHidden = (pWS->colinfo.col[i].flags&1);
1248
1.62k
        if (pWS->colinfo.col[i].first<=pWS->rows.lastcol)
1249
764
            fcol=pWS->colinfo.col[i].first;
1250
865
        else
1251
865
            fcol=pWS->rows.lastcol;
1252
1253
1.62k
        if (pWS->colinfo.col[i].last<=pWS->rows.lastcol)
1254
915
            lcol=pWS->colinfo.col[i].last;
1255
714
        else
1256
714
            lcol=pWS->rows.lastcol;
1257
1258
20.5M
        for (ii=0;ii<=pWS->rows.lastrow;ii++) {
1259
266M
            for (t=fcol;t<=lcol;t++) {
1260
245M
                pWS->rows.row[ii].cells.cell[t].isHidden |= isHidden;
1261
245M
                pWS->rows.row[ii].cells.cell[t].width = width;
1262
245M
            }
1263
20.5M
        }
1264
1.62k
    }
1265
8.43k
    return LIBXLS_OK;
1266
8.43k
}
1267
1268
xls_error_t xls_parseWorkSheet(xlsWorkSheet* pWS)
1269
26.3k
{
1270
26.3k
    if(!pWS) return LIBXLS_ERROR_NULL_ARGUMENT;
1271
1272
26.3k
    BOF tmp;
1273
26.3k
    BYTE* buf = NULL;
1274
26.3k
  long offset = pWS->filepos;
1275
26.3k
    size_t read;
1276
26.3k
    xls_error_t retval = 0;
1277
1278
26.3k
  struct st_cell_data *cell = NULL;
1279
26.3k
  xlsWorkBook *pWB = pWS->workbook;
1280
1281
26.3k
    verbose ("xls_parseWorkSheet");
1282
1283
26.3k
    if ((retval = xls_preparseWorkSheet(pWS)) != LIBXLS_OK) {
1284
17.8k
        goto cleanup;
1285
17.8k
    }
1286
  // printf("size=%d fatpos=%d)\n", pWS->workbook->olestr->size, pWS->workbook->olestr->fatpos);
1287
1288
8.43k
    if ((retval = xls_makeTable(pWS)) != LIBXLS_OK) {
1289
0
        goto cleanup;
1290
0
    }
1291
1292
8.43k
    if ((retval = xls_formatColumn(pWS)) != LIBXLS_OK) {
1293
0
        goto cleanup;
1294
0
    }
1295
1296
8.43k
    if (ole2_seek(pWS->workbook->olestr,pWS->filepos) == -1) {
1297
0
        retval = LIBXLS_ERROR_SEEK;
1298
0
        goto cleanup;
1299
0
    }
1300
8.43k
    do
1301
972k
    {
1302
972k
    long lastPos = offset;
1303
1304
972k
    if(xls_debug > 10) {
1305
0
      printf("LASTPOS=%ld pos=%d filePos=%d filePos=%d\n", lastPos, (int)pWB->olestr->pos, pWS->filepos, pWB->filepos);
1306
0
    }
1307
972k
    if((read = ole2_read(&tmp, 1, 4, pWS->workbook->olestr)) != 4) {
1308
0
            if (xls_debug) fprintf(stderr, "Error: failed to read OLE size\n");
1309
0
            retval = LIBXLS_ERROR_READ;
1310
0
            goto cleanup;
1311
0
        }
1312
972k
        xlsConvertBof((BOF *)&tmp);
1313
972k
        if (tmp.size) {
1314
460k
            BYTE *new_buf = realloc(buf, tmp.size);
1315
460k
            if (new_buf == NULL) {
1316
0
                if (xls_debug) fprintf(stderr, "Error: failed to allocate buffer of size %d\n", (int)tmp.size);
1317
0
                retval = LIBXLS_ERROR_MALLOC;
1318
0
                goto cleanup;
1319
0
            }
1320
460k
            buf = new_buf;
1321
460k
            memset(buf, 0, tmp.size);
1322
460k
            if((read = ole2_read(buf, 1, tmp.size, pWS->workbook->olestr)) != tmp.size) {
1323
0
                if (xls_debug) fprintf(stderr, "Error: failed to read OLE block\n");
1324
0
                retval = LIBXLS_ERROR_READ;
1325
0
                goto cleanup;
1326
0
            }
1327
460k
        }
1328
972k
    offset += 4 + tmp.size;
1329
1330
972k
    if(xls_debug)
1331
0
      xls_showBOF(&tmp);
1332
1333
972k
        switch (tmp.id)
1334
972k
        {
1335
2.94k
        case XLS_RECORD_EOF:
1336
2.94k
            break;
1337
2.73k
        case XLS_RECORD_MERGEDCELLS:
1338
2.73k
            if ((retval = xls_mergedCells(pWS,&tmp,buf)) != LIBXLS_OK) {
1339
1.65k
                goto cleanup;
1340
1.65k
            }
1341
1.07k
            break;
1342
1.07k
        case XLS_RECORD_ROW:
1343
956
            if (tmp.size < sizeof(ROW)) {
1344
0
                retval = LIBXLS_ERROR_PARSE;
1345
0
                goto cleanup;
1346
0
            }
1347
956
      if(xls_debug > 10) printf("ROW: %x at pos=%ld\n", tmp.id, lastPos);
1348
956
            xlsConvertRow((ROW *)buf);
1349
956
            if ((retval = xls_addRow(pWS,(ROW*)buf)) != LIBXLS_OK) {
1350
0
                goto cleanup;
1351
0
            }
1352
956
            break;
1353
956
    case XLS_RECORD_DEFCOLWIDTH:
1354
791
            if (tmp.size < sizeof(WORD)) {
1355
0
                retval = LIBXLS_ERROR_PARSE;
1356
0
                goto cleanup;
1357
0
            }
1358
791
      if(xls_debug > 10) printf("DEFAULT COL WIDTH: %d\n", ((WORD *)buf)[0]);
1359
791
      break;
1360
1.34k
    case XLS_RECORD_DEFAULTROWHEIGHT:
1361
1.34k
            if (tmp.size < 2 * sizeof(WORD)) {
1362
200
                retval = LIBXLS_ERROR_PARSE;
1363
200
                goto cleanup;
1364
200
            }
1365
1.14k
      if(xls_debug > 10) printf("DEFAULT ROW Height: 0x%x %d\n", ((WORD *)buf)[0], ((WORD *)buf)[1]);
1366
1.14k
      break;
1367
329
    case XLS_RECORD_DBCELL:
1368
329
      if(xls_debug > 10) {
1369
0
        DWORD *foo = (DWORD *)buf;
1370
0
                WORD *goo;
1371
0
        int i;
1372
0
                printf("DBCELL: size %d\n", tmp.size);
1373
0
        printf("DBCELL OFFSET=%4.4u -> ROW %ld\n", foo[0], lastPos-foo[0]);
1374
0
        ++foo;
1375
0
        goo = (WORD *)foo;
1376
0
        for(i=0; i<5; ++i) printf("goo[%d]=%4.4x %u\n", i, goo[i], goo[i]);
1377
0
      }
1378
329
      break;
1379
450
        case XLS_RECORD_INDEX:
1380
450
      if(xls_debug > 10) {
1381
0
        DWORD *foo = (DWORD *)buf;
1382
0
                int i;
1383
0
        printf("INDEX: size %d\n", tmp.size);
1384
0
        for(i=0; i<5; ++i) printf("FOO[%d]=%4.4x %u\n", i, foo[i], foo[i]);
1385
0
      }
1386
#if 0
1387
      0 4 4 4 8 4
1388
      12  4 16  4∙nm
1389
      Not used Index to first used row (rf, 0-based) Index to first row of unused tail of sheet (rl, last used row + 1, 0-based)
1390
      Absolute stream position of the DEFCOLWIDTH record (➜5.32) of the current sheet. If this record does not exist, the offset points to the record at the position where the DEFCOLWIDTH record would occur.
1391
      Array of nm absolute stream positions to the DBCELL record (➜5.29) of each Row Block
1392
#endif
1393
450
            break;
1394
2.94k
        case XLS_RECORD_MULRK:
1395
5.49k
        case XLS_RECORD_MULBLANK:
1396
7.26k
        case XLS_RECORD_NUMBER:
1397
10.0k
        case XLS_RECORD_BOOLERR:
1398
12.7k
        case XLS_RECORD_RK:
1399
16.7k
        case XLS_RECORD_LABELSST:
1400
17.8k
        case XLS_RECORD_BLANK:
1401
18.4k
        case XLS_RECORD_LABEL:
1402
21.1k
        case XLS_RECORD_RSTRING:
1403
23.5k
        case XLS_RECORD_FORMULA:
1404
27.0k
        case XLS_RECORD_FORMULA_ALT:
1405
27.0k
            if ((cell = xls_addCell(pWS, &tmp, buf)) == NULL) {
1406
904
                retval = LIBXLS_ERROR_PARSE;
1407
904
                goto cleanup;
1408
904
            }
1409
26.1k
            break;
1410
26.1k
    case XLS_RECORD_ARRAY:
1411
848
      if(formula_handler) formula_handler(tmp.id, tmp.size, buf);
1412
848
      break;
1413
1414
7.43k
    case XLS_RECORD_STRING:
1415
7.43k
      if(cell && (cell->id == XLS_RECORD_FORMULA || cell->id == XLS_RECORD_FORMULA_ALT)) {
1416
3.84k
                xls_cell_set_str(cell, get_string((char *)buf, tmp.size,
1417
3.84k
                            (BYTE)!pWB->is5ver, pWB));
1418
3.84k
        if (xls_debug) xls_showCell(cell);
1419
3.84k
      }
1420
7.43k
      break;
1421
1422
927k
        default:
1423
927k
      if(xls_debug)
1424
0
      {
1425
        //xls_showBOF(&tmp);
1426
0
                if (tmp.size >= sizeof(COL)) {
1427
0
                    printf("   [%d:%d]: 0x%X at pos=%lu size=%u\n", xlsShortVal(((COL*)buf)->row), xlsShortVal(((COL*)buf)->col),
1428
0
                            tmp.id, lastPos, tmp.size);
1429
0
                } else {
1430
0
                    printf("   0x%X at pos=%lu size=%u\n", tmp.id, lastPos, tmp.size);
1431
0
                }
1432
0
      }
1433
927k
            break;
1434
972k
        }
1435
972k
    }
1436
970k
    while ((!pWS->workbook->olestr->eof)&&(tmp.id!=XLS_RECORD_EOF));
1437
1438
26.3k
cleanup:
1439
26.3k
    if (buf)
1440
8.39k
        free(buf);
1441
1442
26.3k
    return retval;
1443
8.43k
}
1444
1445
xlsWorkSheet * xls_getWorkSheet(xlsWorkBook* pWB,int num)
1446
26.3k
{
1447
26.3k
    xlsWorkSheet * pWS = NULL;
1448
26.3k
    verbose ("xls_getWorkSheet");
1449
26.3k
    if (num >= 0 && num < (int)pWB->sheets.count) {
1450
26.3k
        pWS = calloc(1, sizeof(xlsWorkSheet));
1451
26.3k
        if (pWS == NULL)
1452
0
            return NULL;
1453
26.3k
        pWS->filepos=pWB->sheets.sheet[num].filepos;
1454
26.3k
        pWS->workbook=pWB;
1455
26.3k
        pWS->rows.lastcol=0;
1456
26.3k
        pWS->rows.lastrow=0;
1457
26.3k
        pWS->colinfo.count=0;
1458
26.3k
    }
1459
26.3k
    return pWS;
1460
26.3k
}
1461
1462
/* Streams larger than this are not plausible property sets; skip them rather
1463
 * than let a corrupt directory entry drive a huge allocation. */
1464
80
#define XLS_MAX_SUMMARY_STREAM_SIZE (16 * 1024 * 1024)
1465
1466
/* Read an optional property-set stream (SummaryInformation or
1467
 * DocumentSummaryInformation) into a buffer sized to the stream. A missing
1468
 * stream is not an error. See https://github.com/libxls/libxls/issues/121 */
1469
static xls_error_t xls_readSummaryStream(xlsWorkBook *pWB, OLE2 *ole,
1470
4.88k
        const char *name, char **out, size_t *out_len) {
1471
4.88k
    ssize_t bytes_read;
1472
1473
4.88k
    *out = NULL;
1474
4.88k
    *out_len = 0;
1475
1476
4.88k
    if (!(pWB->olestr = ole2_fopen(ole, name)))
1477
4.79k
        return LIBXLS_OK;
1478
1479
89
    if (pWB->olestr->size == 0 || pWB->olestr->size > XLS_MAX_SUMMARY_STREAM_SIZE) {
1480
30
        if (xls_debug) fprintf(stderr, "Skipping %s stream of %zu bytes\n",
1481
0
                name + 1, pWB->olestr->size);
1482
30
        ole2_fclose(pWB->olestr);
1483
30
        pWB->olestr = NULL;
1484
30
        return LIBXLS_OK;
1485
30
    }
1486
1487
59
    if ((*out = calloc(1, pWB->olestr->size)) == NULL)
1488
0
        return LIBXLS_ERROR_MALLOC;
1489
1490
59
    bytes_read = ole2_read(*out, 1, pWB->olestr->size, pWB->olestr);
1491
59
    if (bytes_read == -1) {
1492
2
        if (xls_debug) fprintf(stderr, "%s not found\n", name + 1);
1493
2
        return LIBXLS_ERROR_READ;
1494
2
    }
1495
57
    *out_len = bytes_read;
1496
1497
57
    ole2_fclose(pWB->olestr);
1498
57
    pWB->olestr = NULL;
1499
57
    return LIBXLS_OK;
1500
59
}
1501
1502
2.44k
static xlsWorkBook *xls_open_ole(OLE2 *ole, const char *charset, xls_error_t *outError) {
1503
2.44k
    xlsWorkBook* pWB;
1504
2.44k
    xls_error_t retval = LIBXLS_OK;
1505
1506
2.44k
    pWB = calloc(1, sizeof(xlsWorkBook));
1507
2.44k
    if (pWB == NULL) {
1508
0
        ole2_close(ole);
1509
0
        if (outError)
1510
0
            *outError = LIBXLS_ERROR_MALLOC;
1511
0
        return NULL;
1512
0
    }
1513
2.44k
    verbose ("xls_open_ole");
1514
1515
2.44k
    retval = xls_readSummaryStream(pWB, ole, "\005SummaryInformation",
1516
2.44k
            &pWB->summary, &pWB->summary_len);
1517
2.44k
    if (retval != LIBXLS_OK)
1518
1
        goto cleanup;
1519
1520
2.44k
    retval = xls_readSummaryStream(pWB, ole, "\005DocumentSummaryInformation",
1521
2.44k
            &pWB->docSummary, &pWB->docSummary_len);
1522
2.44k
    if (retval != LIBXLS_OK)
1523
1
        goto cleanup;
1524
1525
#if 0
1526
  if(xls_debug) {
1527
    printf("summary=%d docsummary=%d\n", pWB->summary ? 1 : 0, pWB->docSummary ? 1 : 0);
1528
    xlsSummaryInfo *si = xls_summaryInfo(pWB);
1529
    printf("title=%s\n", si->title);
1530
    printf("subject=%s\n", si->subject);
1531
    printf("author=%s\n", si->author);
1532
    printf("keywords=%s\n", si->keywords);
1533
    printf("comment=%s\n", si->comment);
1534
    printf("lastAuthor=%s\n", si->lastAuthor);
1535
    printf("appName=%s\n", si->appName);
1536
    printf("category=%s\n", si->category);
1537
    printf("manager=%s\n", si->manager);
1538
    printf("company=%s\n", si->company);
1539
  }
1540
#endif
1541
1542
    // open Workbook
1543
2.43k
    if (!(pWB->olestr=ole2_fopen(ole,"Workbook")) && !(pWB->olestr=ole2_fopen(ole,"Book")))
1544
432
    {
1545
432
        if(xls_debug) fprintf(stderr, "Workbook not found\n");
1546
432
        retval = LIBXLS_ERROR_PARSE;
1547
432
        goto cleanup;
1548
432
    }
1549
1550
2.00k
    pWB->sheets.count=0;
1551
2.00k
    pWB->xfs.count=0;
1552
2.00k
    pWB->fonts.count=0;
1553
2.00k
    pWB->charset = strdup(charset ? charset : "UTF-8");
1554
2.00k
    if (pWB->charset == NULL) {
1555
0
        retval = LIBXLS_ERROR_MALLOC;
1556
0
        goto cleanup;
1557
0
    }
1558
1559
2.00k
    retval = xls_parseWorkBook(pWB);
1560
1561
2.44k
cleanup:
1562
2.44k
    if (retval != LIBXLS_OK) {
1563
1.01k
        if (!pWB->olestr)
1564
432
            ole2_close(ole);
1565
1.01k
        xls_close_WB(pWB);
1566
1.01k
        pWB = NULL;
1567
1.01k
    }
1568
2.44k
    if (outError)
1569
0
        *outError = retval;
1570
1571
2.44k
    return pWB;
1572
2.00k
}
1573
1574
xlsWorkBook* xls_open(const char *file, const char* charset)
1575
0
{
1576
0
    return xls_open_file(file, charset, NULL);
1577
0
}
1578
1579
0
xlsWorkBook* xls_open_file(const char *file, const char* charset, xls_error_t *outError) {
1580
0
    OLE2* ole = NULL;
1581
1582
0
    if (!(ole=ole2_open_file(file)))
1583
0
    {
1584
0
        if (xls_debug) fprintf(stderr, "File \"%s\" not found\n",file);
1585
0
        if (outError) *outError = LIBXLS_ERROR_OPEN;
1586
0
        return NULL;
1587
0
    }
1588
1589
0
    return xls_open_ole(ole, charset, outError);
1590
0
}
1591
1592
xlsWorkBook *xls_open_buffer(const unsigned char *buffer, size_t len,
1593
3.72k
        const char *charset, xls_error_t *outError) {
1594
3.72k
    OLE2* ole = NULL;
1595
1596
3.72k
    if (!(ole=ole2_open_buffer(buffer, len)))
1597
1.28k
    {
1598
1.28k
        if (outError) *outError = LIBXLS_ERROR_OPEN;
1599
1.28k
        return NULL;
1600
1.28k
    }
1601
1602
2.44k
    return xls_open_ole(ole, charset, outError);
1603
3.72k
}
1604
1605
xlsRow *xls_row(xlsWorkSheet* pWS, WORD cellRow)
1606
0
{
1607
0
    if(cellRow > pWS->rows.lastrow)
1608
0
        return NULL;
1609
1610
0
    if (pWS->rows.row == NULL)
1611
0
        return NULL;
1612
1613
0
    return &pWS->rows.row[cellRow];
1614
0
}
1615
1616
xlsCell *xls_cell(xlsWorkSheet* pWS, WORD cellRow, WORD cellCol)
1617
0
{
1618
0
    struct st_row_data  *row;
1619
1620
0
    if ((row = xls_row(pWS, cellRow)) == NULL)
1621
0
        return NULL;
1622
1623
0
    if(cellCol >= row->cells.count)
1624
0
        return NULL;
1625
1626
0
    return &row->cells.cell[cellCol];
1627
0
}
1628
1629
void xls_close_WB(xlsWorkBook* pWB)
1630
2.44k
{
1631
2.44k
  OLE2*   ole;
1632
1633
2.44k
  verbose ("xls_close");
1634
1635
2.44k
  if(!pWB) return;
1636
1637
    // OLE first
1638
2.44k
    if (pWB->olestr) {
1639
2.00k
        ole=pWB->olestr->ole;
1640
2.00k
        ole2_fclose(pWB->olestr);
1641
2.00k
        ole2_close(ole);
1642
2.00k
    }
1643
1644
    // WorkBook
1645
2.44k
    free(pWB->charset);
1646
1647
    // Sheets
1648
2.44k
    {
1649
2.44k
        DWORD i;
1650
29.6k
        for(i=0; i<pWB->sheets.count; ++i) {
1651
27.1k
            free(pWB->sheets.sheet[i].name);
1652
27.1k
        }
1653
2.44k
        free(pWB->sheets.sheet);
1654
2.44k
    }
1655
1656
    // SST
1657
2.44k
    {
1658
2.44k
        DWORD i;
1659
2.44k
        if (pWB->sst.string) {
1660
3.77G
            for(i=0; i<pWB->sst.count; ++i) {
1661
3.77G
                free(pWB->sst.string[i].str);
1662
3.77G
            }
1663
359
        }
1664
2.44k
        free(pWB->sst.string);
1665
2.44k
    }
1666
1667
    // xfs
1668
2.44k
    {
1669
2.44k
        free(pWB->xfs.xf);
1670
2.44k
    }
1671
1672
    // fonts
1673
2.44k
    {
1674
2.44k
        DWORD i;
1675
3.26k
        for(i=0; i<pWB->fonts.count; ++i) {
1676
821
            free(pWB->fonts.font[i].name);
1677
821
        }
1678
2.44k
        free(pWB->fonts.font);
1679
2.44k
    }
1680
1681
    // formats
1682
2.44k
    {
1683
2.44k
        DWORD i;
1684
2.88k
        for(i=0; i<pWB->formats.count; ++i) {
1685
448
            free(pWB->formats.format[i].value);
1686
448
        }
1687
2.44k
        free(pWB->formats.format);
1688
2.44k
    }
1689
1690
    // buffers
1691
2.44k
  if(pWB->summary)  free(pWB->summary);
1692
2.44k
  if(pWB->docSummary) free(pWB->docSummary);
1693
1694
2.44k
#ifdef HAVE_ICONV
1695
2.44k
    if (pWB->converter)
1696
85
        iconv_close((iconv_t)pWB->converter);
1697
2.44k
    if (pWB->utf16_converter)
1698
505
        iconv_close((iconv_t)pWB->utf16_converter);
1699
2.44k
#endif
1700
1701
2.44k
    if (pWB->utf8_locale)
1702
0
        xls_freelocale((xls_locale_t)pWB->utf8_locale);
1703
1704
    // TODO - free other dynamically allocated objects like string table??
1705
2.44k
    free(pWB);
1706
2.44k
}
1707
1708
void xls_close_WS(xlsWorkSheet* pWS)
1709
26.3k
{
1710
26.3k
  if(!pWS) return;
1711
1712
26.3k
    if (pWS->rows.row) {
1713
8.43k
        DWORD i, j;
1714
86.0M
        for(j=0; j<=pWS->rows.lastrow; ++j) {
1715
86.0M
            struct st_row_data *row = &pWS->rows.row[j];
1716
86.0M
            if (row->cells.cell) {
1717
5.07G
                for(i=0; i<row->cells.count; ++i) {
1718
4.98G
                    free(row->cells.cell[i].str);
1719
4.98G
                }
1720
86.0M
            }
1721
86.0M
            free(row->cells.cell);
1722
86.0M
        }
1723
8.43k
        free(pWS->rows.row);
1724
8.43k
    }
1725
1726
    // COLINFO
1727
26.3k
    {
1728
26.3k
        free(pWS->colinfo.col);
1729
26.3k
    }
1730
26.3k
    free(pWS);
1731
26.3k
}
1732
1733
const char* xls_getVersion(void)
1734
0
{
1735
0
    return PACKAGE_VERSION;
1736
0
}
1737
1738
0
const char* xls_getError(xls_error_t code) {
1739
0
    if (code == LIBXLS_OK)
1740
0
        return "No error";
1741
0
    if (code == LIBXLS_ERROR_READ)
1742
0
        return "Unable to read from file";
1743
0
    if (code == LIBXLS_ERROR_OPEN)
1744
0
        return "Unable to open file";
1745
0
    if (code == LIBXLS_ERROR_SEEK)
1746
0
        return "Unable to seek within file";
1747
0
    if (code == LIBXLS_ERROR_MALLOC)
1748
0
        return "Unable to allocate memory";
1749
0
    if (code == LIBXLS_ERROR_PARSE)
1750
0
        return "Unable to parse file";
1751
0
    if (code == LIBXLS_ERROR_UNSUPPORTED_ENCRYPTION)
1752
0
        return "Unsupported encryption scheme";
1753
1754
0
    return "Unknown error";
1755
0
}
1756
1757
//
1758
// http://poi.apache.org/hpsf/internals.html
1759
// or google "DocumentSummaryInformation and UserDefined Property Sets" and look for MSDN hits
1760
//
1761
1762
xlsSummaryInfo *xls_summaryInfo(xlsWorkBook* pWB)
1763
0
{
1764
0
  xlsSummaryInfo  *pSI;
1765
1766
0
  pSI = (xlsSummaryInfo *)calloc(1, sizeof(xlsSummaryInfo));
1767
0
  if (pSI == NULL)
1768
0
    return NULL;
1769
0
  xls_dumpSummary(pWB->summary, pWB->summary_len, 1, pSI);
1770
0
  xls_dumpSummary(pWB->docSummary, pWB->docSummary_len, 0, pSI);
1771
1772
0
  return pSI;
1773
0
}
1774
1775
void xls_close_summaryInfo(xlsSummaryInfo *pSI)
1776
0
{
1777
0
  if(!pSI) return;
1778
1779
0
  if(pSI->title)   free(pSI->title);
1780
0
  if(pSI->subject) free(pSI->subject);
1781
0
  if(pSI->author)   free(pSI->author);
1782
0
  if(pSI->keywords) free(pSI->keywords);
1783
0
  if(pSI->comment) free(pSI->comment);
1784
0
  if(pSI->lastAuthor) free(pSI->lastAuthor);
1785
0
  if(pSI->appName) free(pSI->appName);
1786
0
  if(pSI->category) free(pSI->category);
1787
0
  if(pSI->manager) free(pSI->manager);
1788
0
  if(pSI->company) free(pSI->company);
1789
1790
0
  free(pSI);
1791
0
}
1792
1793
0
static void xls_dumpSummary(char *buf, size_t size, int isSummary, xlsSummaryInfo *pSI) {
1794
0
  header      *head;
1795
0
  sectionList   *secList;
1796
0
  propertyList  *plist;
1797
0
  sectionHeader *secHead;
1798
0
  property    *prop;
1799
0
  size_t      sectionOffset, sectionLength, propertyOffset, propertyDataSize;
1800
0
  uint32_t i, j;
1801
1802
0
  if(!buf || size < offsetof(header, secList)) return; // perhaps the document was missing??
1803
1804
0
  head = (header *)buf;
1805
  //printf("header: \n");
1806
  //printf("  sig=%x\n", head->sig);
1807
  //printf("  os=%x\n", head->os >> 16);
1808
  //printf("  class=%8.8x%8.8x%8.8x%8.8x\n", head->format[0], head->format[1], head->format[2], head->format[3]);
1809
  //printf("  count=%x\n", head->count);
1810
1811
0
  if (head->count > (size - offsetof(header, secList)) / sizeof(sectionList)) return;
1812
1813
0
  for(i=0; i<head->count; ++i) {
1814
0
    secList = &head->secList[i];
1815
    //printf("Section %d:\n", i);
1816
    //printf("  class=%8.8x%8.8x%8.8x%8.8x\n", secList->format[0], secList->format[1], secList->format[2], secList->format[3]);
1817
    //printf("  offset=%d (now at %ld\n", secList->offset, (char *)secList - (char *)buf + sizeof(sectionList));
1818
1819
1820
0
    sectionOffset = secList->offset;
1821
0
    if (sectionOffset > size ||
1822
0
      offsetof(sectionHeader, properties) > size - sectionOffset)
1823
0
      continue;
1824
1825
0
    secHead = (sectionHeader *)((char *)head + sectionOffset);
1826
0
    sectionLength = secHead->length;
1827
0
    if (sectionLength < offsetof(sectionHeader, properties) ||
1828
0
      sectionLength > size - sectionOffset ||
1829
0
      secHead->numProperties >
1830
0
        (sectionLength - offsetof(sectionHeader, properties)) / sizeof(propertyList))
1831
0
      continue;
1832
    //printf("  len=%d\n", secHead->length);
1833
    //printf("  properties=%d\n", secHead->numProperties);
1834
0
    for(j=0; j<secHead->numProperties; ++j) {
1835
0
      BYTE **s;
1836
1837
0
      plist = &secHead->properties[j];
1838
      //printf("      ---------\n");
1839
      //printf("      propID=%d offset=%d\n", plist->propertyID, plist->sectionOffset);
1840
0
      propertyOffset = plist->sectionOffset;
1841
0
      if (propertyOffset > sectionLength ||
1842
0
        offsetof(property, data) > sectionLength - propertyOffset)
1843
0
        continue;
1844
1845
0
      prop = (property *)((char *)secHead + propertyOffset);
1846
0
      propertyDataSize = sectionLength - propertyOffset - offsetof(property, data);
1847
      //printf("      propType=%d\n", prop->propertyID);
1848
1849
0
      switch(prop->propertyID) {
1850
0
      case 2:
1851
        //printf("      xlsShortVal=%x\n", *(uint16_t *)prop->data);
1852
0
        break;
1853
0
      case 3:
1854
        //printf("      wordVal=%x\n", *(uint32_t *)prop->data);
1855
0
        break;
1856
0
      case 30:
1857
        //printf("      longVal=%llx\n", *(uint64_t *)prop->data);
1858
        //printf("      s[%u]=%s\n", *(uint32_t  *)prop->data, (char *)prop->data + 4);
1859
0
        if(isSummary) {
1860
0
          switch(plist->propertyID) {
1861
0
          case 2:   s = &pSI->title;    break;
1862
0
          case 3:   s = &pSI->subject;    break;
1863
0
          case 4:   s = &pSI->author;   break;
1864
0
          case 5:   s = &pSI->keywords;   break;
1865
0
          case 6:   s = &pSI->comment;    break;
1866
0
          case 8:   s = &pSI->lastAuthor; break;
1867
0
          case 18:  s = &pSI->appName;    break;
1868
0
          default:  s = NULL;       break;
1869
0
          }
1870
0
        } else {
1871
0
          switch(plist->propertyID) {
1872
0
          case 2:   s = &pSI->category;   break;
1873
0
          case 14:  s = &pSI->manager;    break;
1874
0
          case 15:  s = &pSI->company;    break;
1875
0
          default:  s = NULL;       break;
1876
0
          }
1877
0
        }
1878
0
        if (s && propertyDataSize >= sizeof(uint32_t)) {
1879
0
          uint32_t stringLength = prop->data[0];
1880
0
          char *string = (char *)prop->data + sizeof(uint32_t);
1881
0
          if (stringLength &&
1882
0
            stringLength <= propertyDataSize - sizeof(uint32_t) &&
1883
0
            string[stringLength - 1] == '\0') {
1884
0
            free(*s);
1885
0
            *s = (BYTE *)strdup(string);
1886
0
          }
1887
0
        }
1888
0
        break;
1889
0
      case 64:
1890
        //printf("      longVal=%llx\n", *(uint64_t *)prop->data);
1891
0
        break;
1892
0
      case 65:
1893
#if 0
1894
        {
1895
        uint32_t k;
1896
        for(k=0; k<*(uint32_t  *)prop->data; ++k) {
1897
        unsigned char *t = (unsigned char *)prop->data + 4 + k;
1898
        printf(" %2.2x(%c)", *t, *t);
1899
        }
1900
        printf("\n");
1901
        }
1902
#endif
1903
0
        break;
1904
0
      default:
1905
        //printf("      UNKNOWN!\n");
1906
0
        break;
1907
0
      }
1908
0
    }
1909
0
  }
1910
0
}
1911
1912
void xls_set_formula_hander(xls_formula_handler handler)
1913
0
{
1914
0
  formula_handler = handler;
1915
0
}