Coverage Report

Created: 2024-06-17 06:08

/src/libxls/src/xls.c
Line
Count
Source (jump to first uncovered line)
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
6.95k
#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, int isSummary, xlsSummaryInfo *pSI);
81
82
#if defined(_AIX) || defined(__sun)
83
#pragma pack(1)
84
#else
85
#pragma pack(push, 1)
86
#endif
87
88
typedef struct {
89
  uint32_t    format[4];
90
  uint32_t    offset;
91
} sectionList;
92
93
typedef struct {
94
  uint16_t    sig;
95
  uint16_t    _empty;
96
  uint32_t    os;
97
  uint32_t    format[4];
98
  uint32_t    count;
99
  sectionList   secList[1];
100
} header;
101
102
typedef struct {
103
  uint32_t    propertyID;
104
  uint32_t    sectionOffset;
105
} propertyList;
106
107
typedef struct {
108
  uint32_t    length;
109
  uint32_t    numProperties;
110
  propertyList  properties[1];
111
} sectionHeader;
112
113
typedef struct {
114
  uint32_t    propertyID;
115
  uint32_t    data[1];
116
} property;
117
118
#pragma pack(pop)
119
120
int xls(int debug)
121
0
{
122
0
  xls_debug = debug;
123
0
    return 1;
124
0
}
125
126
static xls_error_t xls_addSST(xlsWorkBook* pWB,SST* sst,DWORD size)
127
353
{
128
353
    verbose("xls_addSST");
129
130
353
    pWB->sst.continued=0;
131
353
    pWB->sst.lastln=0;
132
353
    pWB->sst.lastid=0;
133
353
    pWB->sst.lastrt=0;
134
353
    pWB->sst.lastsz=0;
135
136
353
    if (sst->num > (1<<26)) // 64 MB
137
10
        return LIBXLS_ERROR_MALLOC;
138
139
343
    if (pWB->sst.string)
140
1
        return LIBXLS_ERROR_PARSE;
141
142
342
    if ((pWB->sst.string = calloc(pWB->sst.count = sst->num,
143
342
                    sizeof(struct str_sst_string))) == NULL)
144
0
        return LIBXLS_ERROR_MALLOC;
145
146
342
    return xls_appendSST(pWB, sst->strings, size - offsetof(SST, strings));
147
342
}
148
149
static xls_error_t xls_appendSST(xlsWorkBook* pWB, BYTE* buf, DWORD size)
150
2.77k
{
151
2.77k
    DWORD ln; // String character count
152
2.77k
    DWORD ofs;  // Current offset in SST buffer
153
2.77k
    DWORD rt; // Count of rich text formatting runs
154
2.77k
    DWORD sz; // Size of asian phonetic settings block
155
2.77k
    BYTE flag;  // String flags
156
2.77k
    char* ret = NULL;
157
158
2.77k
    if (xls_debug) {
159
0
      printf("xls_appendSST %u\n", size);
160
0
    }
161
162
2.77k
  sz = rt = ln = 0; // kch
163
2.77k
    ofs=0;
164
165
13.5k
  while(ofs<size)
166
10.8k
    {
167
10.8k
        int ln_toread;
168
169
        // Restore state when we're in a continue record
170
        // or read string length
171
10.8k
        if (pWB->sst.continued) {
172
2.20k
            ln=pWB->sst.lastln;
173
2.20k
            rt=pWB->sst.lastrt;
174
2.20k
            sz=pWB->sst.lastsz;
175
8.63k
        } else {
176
8.63k
            if (ofs + 2 > size) {
177
27
                return LIBXLS_ERROR_PARSE;
178
27
            }
179
8.60k
            ln = buf[ofs+0] + (buf[ofs+1] << 8);
180
8.60k
            rt = 0;
181
8.60k
            sz = 0;
182
183
8.60k
            ofs+=2;
184
8.60k
        }
185
186
10.8k
    if (xls_debug) {
187
0
          printf("ln=%u\n", ln);
188
0
    }
189
190
        // Read flags
191
10.8k
        if ( !pWB->sst.continued || (pWB->sst.continued && ln != 0) ) {
192
10.2k
            if (ofs + sizeof(BYTE) > size) {
193
5
                return LIBXLS_ERROR_PARSE;
194
5
            }
195
10.2k
            flag=*(BYTE *)(buf+ofs);
196
10.2k
            ofs++;
197
198
            // Count of rich text formatting runs
199
10.2k
            if (flag & 0x8) {
200
1.56k
                if (ofs + sizeof(WORD) > size) {
201
3
                    return LIBXLS_ERROR_PARSE;
202
3
                }
203
1.56k
                rt = buf[ofs+0] + (buf[ofs+1] << 8);
204
1.56k
                ofs+=2;
205
1.56k
            }
206
207
            // Size of asian phonetic settings block
208
10.2k
            if (flag & 0x4) {
209
1.76k
                if (ofs + sizeof(DWORD) > size) {
210
5
                    return LIBXLS_ERROR_PARSE;
211
5
                }
212
1.75k
                sz = buf[ofs+0] + (buf[ofs+1] << 8) + (buf[ofs+2] << 16) + ((DWORD)buf[ofs+3] << 24);
213
1.75k
                ofs+=4;
214
215
1.75k
        if (xls_debug) {
216
0
          printf("sz=%u\n", sz);
217
0
        }
218
1.75k
            }
219
10.2k
        } else {
220
580
            flag = 0;
221
580
        }
222
223
    // Read characters (compressed or not)
224
10.7k
        ln_toread = 0;
225
10.7k
        if (ln > 0) {
226
4.20k
            if (flag & 0x1) {
227
1.49k
                size_t new_len = 0;
228
1.49k
                ln_toread = min((size-ofs)/2, ln);
229
1.49k
                ret=unicode_decode((char *)buf+ofs, ln_toread*2, pWB);
230
231
1.49k
                if (ret == NULL) {
232
518
                    ret = strdup("*failed to decode utf16*");
233
518
                }
234
235
1.49k
                ln -= ln_toread;
236
1.49k
                ofs+=ln_toread*2;
237
238
1.49k
                if (xls_debug) {
239
0
                    new_len = strlen(ret);
240
0
                  printf("String16SST: %s(%lu)\n", ret, (unsigned long)new_len);
241
0
                }
242
2.70k
            } else {
243
2.70k
                ln_toread = min((size-ofs), ln);
244
245
2.70k
                ret = codepage_decode((char *)buf+ofs, ln_toread, pWB);
246
2.70k
                if (ret == NULL) {
247
14
                    ret = strdup("*failed to decode BIFF5 string*");
248
14
                }
249
250
2.70k
                ln  -= ln_toread;
251
2.70k
                ofs += ln_toread;
252
253
2.70k
                if (xls_debug) {
254
0
                  printf("String8SST: %s(%u) \n",ret,ln);
255
0
                }
256
2.70k
            }
257
6.59k
        } else {
258
6.59k
            ret = strdup("");
259
6.59k
        }
260
261
10.7k
        if (ln_toread > 0 || !pWB->sst.continued) {
262
            // Concat string if it's a continue, or add string in table
263
9.39k
            if (!pWB->sst.continued) {
264
8.59k
                if (pWB->sst.lastid >= pWB->sst.count) {
265
3
                    free(ret);
266
3
                    return LIBXLS_ERROR_PARSE;
267
3
                }
268
8.59k
                pWB->sst.lastid++;
269
8.59k
                pWB->sst.string[pWB->sst.lastid-1].str=ret;
270
8.59k
            } else {
271
806
                char *tmp = pWB->sst.string[pWB->sst.lastid-1].str;
272
806
                if (tmp == NULL) {
273
0
                    free(ret);
274
0
                    return LIBXLS_ERROR_PARSE;
275
0
                }
276
806
                tmp = realloc(tmp, strlen(tmp)+strlen(ret)+1);
277
806
                if (tmp == NULL)  {
278
0
                    free(ret);
279
0
                    return LIBXLS_ERROR_MALLOC;
280
0
                }
281
806
                pWB->sst.string[pWB->sst.lastid-1].str=tmp;
282
806
                memcpy(tmp+strlen(tmp), ret, strlen(ret)+1);
283
806
        free(ret);
284
806
            }
285
286
9.39k
      if (xls_debug) {
287
0
              printf("String %4u: %s<end>\n", pWB->sst.lastid-1, pWB->sst.string[pWB->sst.lastid-1].str);
288
0
      }
289
9.39k
        } else {
290
1.39k
            free(ret);
291
1.39k
  }
292
293
    // Jump list of rich text formatting runs
294
10.7k
        if (ofs < size && rt > 0) {
295
1.13k
            int rt_toread = min((size-ofs)/4, rt);
296
1.13k
            rt -= rt_toread;
297
1.13k
            ofs += rt_toread*4;
298
1.13k
        }
299
300
    // Jump asian phonetic settings block
301
10.7k
        if (ofs < size && sz > 0) {
302
1.61k
            int sz_toread = min((size-ofs), sz);
303
1.61k
            sz -= sz_toread;
304
1.61k
            ofs += sz_toread;
305
1.61k
        }
306
307
10.7k
        pWB->sst.continued=0;
308
10.7k
    }
309
310
    // Save current character count and count of rich text formatting runs and size of asian phonetic settings block
311
2.73k
  if (ln > 0 || rt > 0 || sz > 0) {
312
2.49k
    pWB->sst.continued = 1;
313
2.49k
    pWB->sst.lastln = ln;
314
2.49k
    pWB->sst.lastrt = rt;
315
2.49k
    pWB->sst.lastsz = sz;
316
317
2.49k
    if (xls_debug) {
318
0
      printf("continued: ln=%u, rt=%u, sz=%u\n", ln, rt, sz);
319
0
    }
320
2.49k
  }
321
322
2.73k
    return LIBXLS_OK;
323
2.77k
}
324
325
static double NumFromRk(DWORD drk)
326
8.71k
{
327
8.71k
  double ret;
328
329
  // What kind of value is this ?
330
8.71k
    if (drk & 0x02) {
331
      // Integer value
332
2.99k
    int tmp = (int)drk >> 2;  // cast to keep it negative in < 0
333
2.99k
        ret = (double)tmp;
334
5.72k
    } else {
335
      // Floating point value;
336
5.72k
    unsigned64_t tmp = drk & 0xfffffffc;
337
5.72k
    tmp <<= 32;
338
5.72k
    memcpy(&ret, &tmp, sizeof(unsigned64_t));
339
5.72k
    }
340
    // Is value multiplied by 100 ?
341
8.71k
    if (drk & 0x01) {
342
3.10k
        ret /= 100.0;
343
3.10k
    }
344
8.71k
    return ret;
345
8.71k
}
346
347
static xls_error_t xls_addSheet(xlsWorkBook* pWB, BOUNDSHEET *bs, DWORD size)
348
23.1k
{
349
23.1k
  char * name;
350
23.1k
  DWORD filepos;
351
23.1k
  BYTE visible, type;
352
353
23.1k
  filepos = bs->filepos;
354
23.1k
  visible = bs->visible;
355
23.1k
  type = bs->type;
356
357
  // printf("charset=%s uni=%d\n", pWB->charset, unicode);
358
  // printf("bs name %.*s\n", bs->name[0], bs->name+1);
359
23.1k
  name = get_string(bs->name, size - offsetof(BOUNDSHEET, name), 0, pWB);
360
  // printf("name=%s\n", name);
361
362
23.1k
  if(xls_debug) {
363
0
    printf ("xls_addSheet[0x%x]\n", type);
364
0
    switch (type & 0x0f)
365
0
    {
366
0
    case 0x00:
367
      /* worksheet or dialog sheet */
368
0
      printf ("85: Worksheet or dialog sheet\n");
369
0
      break;
370
0
    case 0x01:
371
      /* Microsoft Excel 4.0 macro sheet */
372
0
      printf ("85: Microsoft Excel 4.0 macro sheet\n");
373
0
      break;
374
0
    case 0x02:
375
      /* Chart */
376
0
      printf ("85: Chart sheet\n");
377
0
      break;
378
0
    case 0x06:
379
      /* Visual Basic module */
380
0
      printf ("85: Visual Basic sheet\n");
381
0
      break;
382
0
    default:
383
0
      printf ("???\n");
384
0
      break;
385
0
    }
386
0
    printf("visible: %x\n", visible);
387
0
    printf("    Pos: %Xh\n",filepos);
388
0
    printf("   type: %.4Xh\n",type);
389
0
    printf("   name: %s\n", name);
390
0
  }
391
392
23.1k
    pWB->sheets.sheet = realloc(pWB->sheets.sheet,(pWB->sheets.count+1)*sizeof (struct st_sheet_data));
393
23.1k
    if (pWB->sheets.sheet == NULL) {
394
0
        free(name);
395
0
        return LIBXLS_ERROR_MALLOC;
396
0
    }
397
398
23.1k
    pWB->sheets.sheet[pWB->sheets.count].name=name;
399
23.1k
    pWB->sheets.sheet[pWB->sheets.count].filepos=filepos;
400
23.1k
    pWB->sheets.sheet[pWB->sheets.count].visibility=visible;
401
23.1k
    pWB->sheets.sheet[pWB->sheets.count].type=type;
402
23.1k
    pWB->sheets.count++;
403
404
23.1k
  return LIBXLS_OK;
405
23.1k
}
406
407
408
static xls_error_t xls_addRow(xlsWorkSheet* pWS,ROW* row)
409
463
{
410
463
    struct st_row_data* tmp;
411
412
    //verbose ("xls_addRow");
413
414
463
    if (row->index > pWS->rows.lastrow)
415
0
        return LIBXLS_ERROR_PARSE;
416
417
463
    tmp=&pWS->rows.row[row->index];
418
463
    tmp->height=row->height;
419
463
    tmp->fcell=row->fcell;
420
463
    tmp->lcell=row->lcell;
421
463
    tmp->flags=row->flags;
422
463
    tmp->xf=row->xf&0xfff;
423
463
    tmp->xfflags=(row->xf >> 8)&0xf0;
424
463
    if(xls_debug) xls_showROW(tmp);
425
426
463
    return LIBXLS_OK;
427
463
}
428
429
static xls_error_t xls_makeTable(xlsWorkSheet* pWS)
430
7.12k
{
431
7.12k
    DWORD i,t;
432
7.12k
    struct st_row_data* tmp;
433
7.12k
    verbose ("xls_makeTable");
434
435
7.12k
    if ((pWS->rows.row = calloc((pWS->rows.lastrow+1),sizeof(struct st_row_data))) == NULL)
436
0
        return LIBXLS_ERROR_MALLOC;
437
438
  // printf("ALLOC: rows=%d cols=%d\n", pWS->rows.lastrow, pWS->rows.lastcol);
439
75.2M
    for (t=0;t<=pWS->rows.lastrow;t++)
440
75.2M
    {
441
75.2M
        tmp=&pWS->rows.row[t];
442
75.2M
        tmp->index=t;
443
75.2M
        tmp->fcell=0;
444
75.2M
        tmp->lcell=pWS->rows.lastcol;
445
446
75.2M
    tmp->cells.count = pWS->rows.lastcol+1;
447
75.2M
        if ((tmp->cells.cell = calloc(tmp->cells.count, sizeof(struct st_cell_data))) == NULL)
448
0
            return LIBXLS_ERROR_MALLOC;
449
450
7.15G
        for (i=0;i<=pWS->rows.lastcol;i++)
451
7.07G
        {
452
7.07G
            tmp->cells.cell[i].col = i;
453
7.07G
            tmp->cells.cell[i].row = t;
454
7.07G
            tmp->cells.cell[i].width = pWS->defcolwidth;
455
7.07G
            tmp->cells.cell[i].id = XLS_RECORD_BLANK;
456
7.07G
        }
457
75.2M
    }
458
7.12k
    return LIBXLS_OK;
459
7.12k
}
460
461
37.0k
int xls_isCellTooSmall(xlsWorkBook* pWB, BOF* bof, BYTE* buf) {
462
37.0k
    if (bof->size < sizeof(COL))
463
1.85k
        return 1;
464
465
35.1k
    if (bof->id == XLS_RECORD_FORMULA || bof->id == XLS_RECORD_FORMULA_ALT)
466
8.24k
        return (bof->size < sizeof(FORMULA));
467
468
26.9k
    if (bof->id == XLS_RECORD_MULRK)
469
3.95k
        return (bof->size < offsetof(MULRK, rk));
470
471
22.9k
    if (bof->id == XLS_RECORD_MULBLANK)
472
5.01k
        return (bof->size < offsetof(MULBLANK, xf));
473
474
17.9k
    if (bof->id == XLS_RECORD_LABELSST)
475
4.95k
        return (bof->size < offsetof(LABEL, value) + (pWB->is5ver ? 2 : 4));
476
477
12.9k
    if (bof->id == XLS_RECORD_LABEL || bof->id == XLS_RECORD_RSTRING) {
478
3.38k
        if (bof->size < offsetof(LABEL, value) + 2)
479
201
            return 1;
480
481
3.18k
        size_t label_len = ((LABEL*)buf)->value[0] + (((LABEL*)buf)->value[1] << 8);
482
3.18k
        if (pWB->is5ver) {
483
550
            return (bof->size < offsetof(LABEL, value) + 2 + label_len);
484
550
        }
485
486
2.63k
        if (bof->size < offsetof(LABEL, value) + 3)
487
195
            return 1;
488
489
2.43k
        if ((((LABEL*)buf)->value[2] & 0x01) == 0) {
490
1.27k
            return (bof->size < offsetof(LABEL, value) + 3 + label_len);
491
1.27k
        }
492
1.16k
        return (bof->size < offsetof(LABEL, value) + 3 + 2 * label_len);
493
2.43k
    }
494
495
9.60k
    if (bof->id == XLS_RECORD_RK)
496
2.73k
        return (bof->size < sizeof(RK));
497
498
6.86k
    if (bof->id == XLS_RECORD_NUMBER)
499
1.90k
        return (bof->size < sizeof(BR_NUMBER));
500
501
4.96k
    if (bof->id == XLS_RECORD_BOOLERR)
502
3.49k
        return (bof->size < sizeof(BOOLERR));
503
504
1.47k
    return 0;
505
4.96k
}
506
507
31.5k
void xls_cell_set_str(struct st_cell_data *cell, char *str) {
508
31.5k
    if (cell->str) {
509
5.59k
        free(cell->str);
510
5.59k
    }
511
31.5k
    cell->str = str;
512
31.5k
}
513
514
static struct st_cell_data *xls_addCell(xlsWorkSheet* pWS,BOF* bof,BYTE* buf)
515
15.2k
{
516
15.2k
    struct st_cell_data*  cell;
517
15.2k
    struct st_row_data*   row;
518
15.2k
    WORD                    col;
519
15.2k
    int           i;
520
521
15.2k
  verbose ("xls_addCell");
522
523
15.2k
    if (xls_isCellTooSmall(pWS->workbook, bof, buf))
524
0
        return NULL;
525
526
  // printf("ROW: %u COL: %u\n", xlsShortVal(((COL*)buf)->row), xlsShortVal(((COL*)buf)->col));
527
15.2k
    row=&pWS->rows.row[xlsShortVal(((COL*)buf)->row)];
528
529
15.2k
    col = xlsShortVal(((COL*)buf)->col);
530
15.2k
    if (col >= row->cells.count) {
531
386
        if (xls_debug) fprintf(stderr, "Error: Column index out of bounds\n");
532
386
        return NULL;
533
386
    }
534
14.8k
    cell = &row->cells.cell[col];
535
536
14.8k
    cell->id=bof->id;
537
14.8k
    cell->xf=xlsShortVal(((COL*)buf)->xf);
538
539
14.8k
    switch (bof->id)
540
14.8k
    {
541
1.54k
    case XLS_RECORD_FORMULA:
542
3.93k
    case XLS_RECORD_FORMULA_ALT:
543
3.93k
    xlsConvertFormula((FORMULA *)buf);
544
3.93k
        cell->id=XLS_RECORD_FORMULA;
545
3.93k
        if (((FORMULA*)buf)->res!=0xffff) {
546
      // if a double, then set double and clear l
547
1.69k
      cell->l=0;
548
1.69k
      memcpy(&cell->d, &((FORMULA*)buf)->resid, sizeof(double));  // Required for ARM
549
1.69k
            cell->id = XLS_RECORD_NUMBER; // hack
550
1.69k
            xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
551
1.69k
            cell->id = bof->id;
552
2.23k
    } else {
553
2.23k
      double d = ((FORMULA*)buf)->resdata[1];
554
2.23k
      cell->l = 0xFFFF;
555
2.23k
      switch(((FORMULA*)buf)->resid) {
556
331
      case 0:   // String
557
331
        break; // cell is half complete, get the STRING next record
558
442
      case 1:   // Boolean
559
442
        memcpy(&cell->d, &d, sizeof(double)); // Required for ARM
560
442
                xls_cell_set_str(cell, strdup("bool"));
561
442
        break;
562
645
      case 2:   // error
563
645
        memcpy(&cell->d, &d, sizeof(double)); // Required for ARM
564
645
                xls_cell_set_str(cell, strdup("error"));
565
645
        break;
566
452
      case 3:   // empty string
567
452
                xls_cell_set_str(cell, strdup(""));
568
452
        break;
569
2.23k
      }
570
2.23k
    }
571
3.93k
    if(formula_handler) formula_handler(bof->id, bof->size, buf);
572
3.93k
        break;
573
1.28k
    case XLS_RECORD_MULRK:
574
8.65k
        for (i = 0; i < (bof->size - 6)/6; i++)  // 6 == 2 row + 2 col + 2 trailing index
575
7.56k
        {
576
7.56k
            WORD index = col + i;
577
7.56k
            if(index >= row->cells.count) {
578
194
                if (xls_debug) fprintf(stderr, "Error: MULTI-RK index out of bounds\n");
579
194
                return NULL;
580
194
            }
581
7.36k
            cell=&row->cells.cell[index];
582
7.36k
            cell->id=XLS_RECORD_RK;
583
7.36k
            cell->xf=xlsShortVal(((MULRK*)buf)->rk[i].xf);
584
7.36k
            cell->d=NumFromRk(xlsIntVal(((MULRK*)buf)->rk[i].value));
585
7.36k
            xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
586
7.36k
        }
587
1.09k
        break;
588
1.66k
    case XLS_RECORD_MULBLANK:
589
11.7k
        for (i = 0; i < (bof->size - 6)/2; i++)  // 6 == 2 row + 2 col + 2 trailing index
590
10.3k
        {
591
10.3k
            WORD index = col + i;
592
10.3k
            if(index >= row->cells.count) {
593
206
                if (xls_debug) fprintf(stderr, "Error: MULTI-BLANK index out of bounds\n");
594
206
                return NULL;
595
206
            }
596
10.1k
            cell=&row->cells.cell[index];
597
10.1k
            cell->id=XLS_RECORD_BLANK;
598
10.1k
            cell->xf=xlsShortVal(((MULBLANK*)buf)->xf[i]);
599
10.1k
            xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
600
10.1k
        }
601
1.45k
        break;
602
2.18k
    case XLS_RECORD_LABELSST:
603
2.97k
    case XLS_RECORD_LABEL:
604
3.55k
    case XLS_RECORD_RSTRING:
605
3.55k
        xls_cell_set_str(cell, xls_getfcell(pWS->workbook, cell, ((LABEL*)buf)->value));
606
3.55k
        if (cell->str) {
607
1.01k
            sscanf((char *)cell->str, "%d", &cell->l);
608
1.01k
            sscanf((char *)cell->str, "%lf", &cell->d);
609
1.01k
        }
610
3.55k
    break;
611
1.34k
    case XLS_RECORD_RK:
612
1.34k
        cell->d=NumFromRk(xlsIntVal(((RK*)buf)->value));
613
1.34k
        xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
614
1.34k
        break;
615
518
    case XLS_RECORD_BLANK:
616
518
        break;
617
874
    case XLS_RECORD_NUMBER:
618
874
        xlsConvertDouble((BYTE *)&((BR_NUMBER*)buf)->value);
619
874
    memcpy(&cell->d, &((BR_NUMBER*)buf)->value, sizeof(double)); // Required for ARM
620
874
        xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
621
874
        break;
622
1.67k
    case XLS_RECORD_BOOLERR:
623
1.67k
        cell->d = ((BOOLERR *)buf)->value;
624
1.67k
        if (((BOOLERR *)buf)->iserror) {
625
739
            xls_cell_set_str(cell, strdup("error"));
626
935
        } else {
627
935
            xls_cell_set_str(cell, strdup("bool"));
628
935
        }
629
1.67k
        break;
630
0
    default:
631
0
        xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
632
0
        break;
633
14.8k
    }
634
14.4k
    if (xls_debug) xls_showCell(cell);
635
636
14.4k
  return cell;
637
14.8k
}
638
639
static char *xls_addFont(xlsWorkBook* pWB, FONT* font, DWORD size)
640
784
{
641
784
    struct st_font_data* tmp;
642
643
784
    verbose("xls_addFont");
644
645
784
    pWB->fonts.font = realloc(pWB->fonts.font,(pWB->fonts.count+1)*sizeof(struct st_font_data));
646
784
    if (pWB->fonts.font == NULL)
647
0
        return NULL;
648
649
784
    tmp=&pWB->fonts.font[pWB->fonts.count];
650
651
784
    tmp->name = get_string(font->name, size - offsetof(FONT, name), 0, pWB);
652
653
784
    tmp->height=font->height;
654
784
    tmp->flag=font->flag;
655
784
    tmp->color=font->color;
656
784
    tmp->bold=font->bold;
657
784
    tmp->escapement=font->escapement;
658
784
    tmp->underline=font->underline;
659
784
    tmp->family=font->family;
660
784
    tmp->charset=font->charset;
661
662
    //  xls_showFont(tmp);
663
784
    pWB->fonts.count++;
664
665
784
  return tmp->name;
666
784
}
667
668
static xls_error_t xls_addFormat(xlsWorkBook* pWB, FORMAT* format, DWORD size)
669
468
{
670
468
    struct st_format_data* tmp;
671
672
468
    verbose("xls_addFormat");
673
468
    pWB->formats.format = realloc(pWB->formats.format, (pWB->formats.count+1)*sizeof(struct st_format_data));
674
468
    if (pWB->formats.format == NULL)
675
0
        return LIBXLS_ERROR_MALLOC;
676
677
468
    tmp = &pWB->formats.format[pWB->formats.count];
678
468
    tmp->index = format->index;
679
468
    tmp->value = get_string(format->value, size - offsetof(FORMAT, value), (BYTE)!pWB->is5ver, pWB);
680
468
    if(xls_debug) xls_showFormat(tmp);
681
468
    pWB->formats.count++;
682
683
468
    return LIBXLS_OK;
684
468
}
685
686
static xls_error_t xls_addXF8(xlsWorkBook* pWB,XF8* xf)
687
1.05k
{
688
1.05k
    struct st_xf_data* tmp;
689
690
1.05k
    verbose("xls_addXF");
691
1.05k
    pWB->xfs.xf= realloc(pWB->xfs.xf, (pWB->xfs.count+1)*sizeof(struct st_xf_data));
692
1.05k
    if (pWB->xfs.xf == NULL)
693
0
        return LIBXLS_ERROR_MALLOC;
694
695
1.05k
    tmp=&pWB->xfs.xf[pWB->xfs.count];
696
697
1.05k
    tmp->font=xf->font;
698
1.05k
    tmp->format=xf->format;
699
1.05k
    tmp->type=xf->type;
700
1.05k
    tmp->align=xf->align;
701
1.05k
    tmp->rotation=xf->rotation;
702
1.05k
    tmp->ident=xf->ident;
703
1.05k
    tmp->usedattr=xf->usedattr;
704
1.05k
    tmp->linestyle=xf->linestyle;
705
1.05k
    tmp->linecolor=xf->linecolor;
706
1.05k
    tmp->groundcolor=xf->groundcolor;
707
708
    //  xls_showXF(tmp);
709
1.05k
    pWB->xfs.count++;
710
711
1.05k
    return LIBXLS_OK;
712
1.05k
}
713
714
static xls_error_t xls_addXF5(xlsWorkBook* pWB,XF5* xf)
715
307
{
716
307
    struct st_xf_data* tmp;
717
718
307
    verbose("xls_addXF");
719
307
    pWB->xfs.xf = realloc(pWB->xfs.xf, (pWB->xfs.count+1)*sizeof(struct st_xf_data));
720
307
    if (pWB->xfs.xf == NULL)
721
0
        return LIBXLS_ERROR_MALLOC;
722
723
307
    tmp=&pWB->xfs.xf[pWB->xfs.count];
724
725
307
    tmp->font=xf->font;
726
307
    tmp->format=xf->format;
727
307
    tmp->type=xf->type;
728
307
    tmp->align=(BYTE)xf->align;
729
/*
730
    tmp->rotation=xf->rotation;
731
    tmp->ident=xf->ident;
732
    tmp->usedattr=xf->usedattr;
733
    tmp->linestyle=xf->linestyle;
734
    tmp->linecolor=xf->linecolor;
735
    tmp->groundcolor=xf->groundcolor;
736
*/
737
738
    //  xls_showXF(tmp);
739
307
    pWB->xfs.count++;
740
307
    return LIBXLS_OK;
741
307
}
742
743
static xls_error_t xls_addColinfo(xlsWorkSheet* pWS,COLINFO* colinfo)
744
1.82k
{
745
1.82k
    struct st_colinfo_data* tmp;
746
747
1.82k
    verbose("xls_addColinfo");
748
1.82k
    pWS->colinfo.col =  realloc(pWS->colinfo.col,(pWS->colinfo.count+1)*sizeof(struct st_colinfo_data));
749
1.82k
    if (pWS->colinfo.col == NULL)
750
0
        return LIBXLS_ERROR_MALLOC;
751
752
1.82k
    tmp=&pWS->colinfo.col[pWS->colinfo.count];
753
1.82k
    tmp->first=colinfo->first;
754
1.82k
    tmp->last=colinfo->last;
755
1.82k
    tmp->width=colinfo->width;
756
1.82k
    tmp->xf=colinfo->xf;
757
1.82k
    tmp->flags=colinfo->flags;
758
759
1.82k
    if(xls_debug) xls_showColinfo(tmp);
760
1.82k
    pWS->colinfo.count++;
761
762
1.82k
    return LIBXLS_OK;
763
1.82k
}
764
765
static xls_error_t xls_mergedCells(xlsWorkSheet* pWS,BOF* bof,BYTE* buf)
766
1.89k
{
767
1.89k
    if (bof->size < sizeof(WORD))
768
217
        return LIBXLS_ERROR_PARSE;
769
770
1.67k
    int count = buf[0] + (buf[1] << 8);
771
1.67k
    DWORD limit = sizeof(WORD)+count*sizeof(struct MERGEDCELLS);
772
1.67k
    if(limit > (DWORD)bof->size) {
773
251
        verbose("Merged Cells Count out of range");
774
251
        return LIBXLS_ERROR_PARSE;
775
251
    }
776
1.42k
    int i,c,r;
777
1.42k
    struct MERGEDCELLS *span;
778
1.42k
    verbose("Merged Cells");
779
4.27k
    for (i=0;i<count;i++)
780
3.73k
    {
781
3.73k
        span=(struct MERGEDCELLS*)(buf+(2+i*sizeof(struct MERGEDCELLS)));
782
3.73k
        xlsConvertMergedcells(span);
783
        //    printf("Merged Cells: [%i,%i] [%i,%i] \n",span->colf,span->rowf,span->coll,span->rowl);
784
        // Sanity check:
785
3.73k
        if(!(   span->rowf <= span->rowl &&
786
3.73k
                span->rowl <= pWS->rows.lastrow &&
787
3.73k
                span->colf <= span->coll &&
788
3.73k
                span->coll <= pWS->rows.lastcol
789
3.73k
        )) {
790
884
            return LIBXLS_ERROR_PARSE;
791
884
        }
792
793
1.65M
        for (r=span->rowf;r<=span->rowl;r++)
794
7.45M
            for (c=span->colf;c<=span->coll;c++)
795
5.80M
                pWS->rows.row[r].cells.cell[c].isHidden=1;
796
2.85k
        pWS->rows.row[span->rowf].cells.cell[span->colf].colspan=(span->coll-span->colf+1);
797
2.85k
        pWS->rows.row[span->rowf].cells.cell[span->colf].rowspan=(span->rowl-span->rowf+1);
798
2.85k
        pWS->rows.row[span->rowf].cells.cell[span->colf].isHidden=0;
799
2.85k
    }
800
538
    return LIBXLS_OK;
801
1.42k
}
802
803
79.0k
int xls_isRecordTooSmall(xlsWorkBook *pWB, BOF *bof1, const BYTE* buf) {
804
79.0k
    switch (bof1->id) {
805
358
        case XLS_RECORD_BOF: // BIFF5-8
806
358
            return (bof1->size < 2 * sizeof(WORD));
807
247
        case XLS_RECORD_CODEPAGE:
808
247
            return (bof1->size < sizeof(WORD));
809
92
    case XLS_RECORD_WINDOW1:
810
92
            return (bof1->size < sizeof(WIND1));
811
354
        case XLS_RECORD_SST:
812
354
            return (bof1->size < offsetof(SST, strings));
813
23.1k
        case XLS_RECORD_BOUNDSHEET:
814
23.1k
            return (bof1->size < offsetof(BOUNDSHEET, name));
815
1.36k
        case XLS_RECORD_XF:
816
1.36k
      if(pWB->is5ver) {
817
308
                return (bof1->size < sizeof(XF5));
818
308
            }
819
1.05k
            return (bof1->size < sizeof(XF8));
820
437
        case XLS_RECORD_FONT:
821
786
        case XLS_RECORD_FONT_ALT:
822
786
            return (bof1->size < offsetof(FONT, name));
823
468
        case XLS_RECORD_FORMAT:
824
468
            return (bof1->size < offsetof(FORMAT, value));
825
996
        case XLS_RECORD_STYLE:
826
996
            {
827
996
                struct {
828
996
                    unsigned short idx;
829
996
                    unsigned char ident;
830
996
                    unsigned char lvl;
831
996
                } *styl;
832
996
                styl = (void *)buf;
833
996
                if(bof1->size < 2) {
834
1
                    return 1;
835
1
                }
836
995
                if(styl->idx & 0x8000) {
837
496
                    return bof1->size < 4;
838
499
                } else {
839
499
                    if(bof1->size < 3) return 1;
840
497
                    return bof1->size < 3 + styl->ident;
841
499
                }
842
995
            }
843
237
    case XLS_RECORD_1904:
844
237
            return (bof1->size < sizeof(BYTE));
845
51.0k
        default:
846
51.0k
            break;
847
79.0k
    }
848
51.0k
    return 0;
849
79.0k
}
850
851
xls_error_t xls_parseWorkBook(xlsWorkBook* pWB)
852
1.89k
{
853
1.89k
    if(!pWB) return LIBXLS_ERROR_NULL_ARGUMENT;
854
855
1.89k
    BOF bof1 = { .id = 0, .size = 0 };
856
1.89k
    BOF bof2 = { .id = 0, .size = 0 };
857
1.89k
    BYTE* buf = NULL;
858
1.89k
  BYTE once = 0;
859
1.89k
    xls_error_t retval = LIBXLS_OK;
860
861
1.89k
    verbose ("xls_parseWorkBook");
862
79.5k
    do {
863
79.5k
    if(xls_debug > 10) {
864
0
      printf("READ WORKBOOK filePos=%ld\n",  (long)pWB->filepos);
865
0
      printf("  OLE: start=%d pos=%u size=%u fatPos=%u\n",
866
0
                    pWB->olestr->start, (unsigned int)pWB->olestr->pos,
867
0
                    (unsigned int)pWB->olestr->size, (unsigned int)pWB->olestr->fatpos); 
868
0
    }
869
870
79.5k
        if (ole2_read(&bof1, 1, 4, pWB->olestr) != 4) {
871
83
            retval = LIBXLS_ERROR_READ;
872
83
            goto cleanup;
873
83
        }
874
79.4k
        xlsConvertBof(&bof1);
875
79.4k
    if(xls_debug) xls_showBOF(&bof1);
876
877
79.4k
        if (bof1.size) {
878
43.3k
            if ((buf = realloc(buf, bof1.size)) == NULL) {
879
0
                if (xls_debug) fprintf(stderr, "Error: failed to allocate buffer of size %d\n", (int)bof1.size);
880
0
                retval = LIBXLS_ERROR_MALLOC;
881
0
                goto cleanup;
882
0
            }
883
43.3k
            if (ole2_read(buf, 1, bof1.size, pWB->olestr) != bof1.size) {
884
348
                if (xls_debug) fprintf(stderr, "Error: failed to read OLE block\n");
885
348
                retval = LIBXLS_ERROR_READ;
886
348
                goto  cleanup;
887
348
            }
888
43.3k
        }
889
890
79.0k
        if (xls_isRecordTooSmall(pWB, &bof1, buf)) {
891
26
            retval = LIBXLS_ERROR_PARSE;
892
26
            goto cleanup;
893
26
        }
894
895
79.0k
        switch (bof1.id) {
896
364
        case XLS_RECORD_EOF:
897
            //verbose("EOF");
898
364
            break;
899
358
        case XLS_RECORD_BOF: // BIFF5-8
900
358
            pWB->is5ver = (buf[0] + (buf[1] << 8) != 0x600);
901
358
            pWB->type = buf[2] + (buf[3] << 8);
902
358
            if(xls_debug) {
903
0
                printf("version: %s\n", pWB->is5ver ? "BIFF5" : "BIFF8" );
904
0
                printf("   type: %.2X\n", pWB->type);
905
0
            }
906
358
            break;
907
908
247
        case XLS_RECORD_CODEPAGE:
909
247
            pWB->codepage = buf[0] + (buf[1] << 8);
910
247
      if(xls_debug) printf("codepage: %d\n", pWB->codepage);
911
247
            break;
912
913
2.79k
        case XLS_RECORD_CONTINUE:
914
2.79k
      if(once) {
915
2.75k
        if (bof2.id==XLS_RECORD_SST) {
916
2.43k
          if ((retval = xls_appendSST(pWB,buf,bof1.size)) != LIBXLS_OK)
917
9
                        goto cleanup;
918
2.43k
                }
919
2.74k
        bof1=bof2;
920
2.74k
      }
921
2.78k
            break;
922
923
2.78k
    case XLS_RECORD_WINDOW1:
924
91
      {
925
91
        WIND1 *w = (WIND1*)buf;
926
91
                xlsConvertWindow(w);
927
91
        pWB->activeSheetIdx = w->itabCur;
928
91
        if(xls_debug) {
929
0
          printf("WINDOW1: ");
930
0
          printf("xWn    : %d\n", w->xWn/20);
931
0
          printf("yWn    : %d\n", w->yWn/20);
932
0
          printf("dxWn   : %d\n", w->dxWn/20);
933
0
          printf("dyWn   : %d\n", w->dyWn/20);
934
0
          printf("grbit  : %d\n", w->grbit);
935
0
          printf("itabCur: %d\n", w->itabCur);
936
0
          printf("itabFi : %d\n", w->itabFirst);
937
0
          printf("ctabSel: %d\n", w->ctabSel);
938
0
          printf("wTabRat: %d\n", w->wTabRatio);
939
0
        }
940
91
      }
941
91
      break;
942
943
353
        case XLS_RECORD_SST:
944
      //printf("ADD SST\n");
945
353
            xlsConvertSst((SST *)buf);
946
353
            if ((retval = xls_addSST(pWB,(SST*)buf,bof1.size)) != LIBXLS_OK) {
947
45
                goto cleanup;
948
45
            }
949
308
            break;
950
951
5.21k
        case XLS_RECORD_EXTSST:
952
5.21k
            break;
953
954
23.1k
        case XLS_RECORD_BOUNDSHEET:
955
23.1k
      {
956
        //printf("ADD SHEET\n");
957
23.1k
        BOUNDSHEET *bs = (BOUNDSHEET *)buf;
958
23.1k
                xlsConvertBoundsheet(bs);
959
        // different for BIFF5 and BIFF8
960
23.1k
                if ((retval = xls_addSheet(pWB, bs, bof1.size)) != LIBXLS_OK) {
961
0
                    goto cleanup;
962
0
                }
963
23.1k
      }
964
23.1k
            break;
965
966
23.1k
        case XLS_RECORD_XF:
967
1.36k
      if(pWB->is5ver) {
968
307
        XF5 *xf;
969
307
        xf = (XF5 *)buf;
970
307
                xlsConvertXf5(xf);
971
972
307
        if ((retval = xls_addXF5(pWB,xf)) != LIBXLS_OK) {
973
0
                    goto cleanup;
974
0
                }
975
307
        if(xls_debug) {
976
0
          printf("   font: %d\n", xf->font);
977
0
          printf(" format: %d\n", xf->format);
978
0
          printf("   type: %.4x\n", xf->type);
979
0
          printf("  align: %.4x\n", xf->align);
980
0
          printf("rotatio: %.4x\n", xf->color);
981
0
          printf("  ident: %.4x\n", xf->fill);
982
0
          printf("usedatt: %.4x\n", xf->border);
983
0
          printf("linesty: %.4x\n", xf->linestyle);
984
0
        }
985
1.05k
      } else {
986
1.05k
        XF8 *xf;
987
1.05k
        xf = (XF8 *)buf;
988
1.05k
                xlsConvertXf8(xf);
989
990
1.05k
        if ((retval = xls_addXF8(pWB,xf)) != LIBXLS_OK) {
991
0
                    goto cleanup;
992
0
                }
993
994
1.05k
        if(xls_debug) {
995
0
          xls_showXF(xf);
996
0
        }
997
1.05k
      }
998
1.36k
            break;
999
1000
1.36k
        case XLS_RECORD_FONT:
1001
784
        case XLS_RECORD_FONT_ALT:
1002
784
      {
1003
784
        char *s;
1004
784
        FONT *f = (FONT*)buf;
1005
784
                xlsConvertFont(f);
1006
784
        s = xls_addFont(pWB,f, bof1.size);
1007
784
        if(xls_debug) {
1008
0
          printf(" height: %d\n", f->height);
1009
0
          printf("   flag: 0x%x\n", f->flag);
1010
0
          printf("  color: 0x%x\n", f->color);
1011
0
          printf(" weight: %d\n", f->bold);
1012
0
          printf("escapem: 0x%x\n", f->escapement);
1013
0
          printf("underln: 0x%x\n", f->underline);
1014
0
          printf(" family: 0x%x\n", f->family);
1015
0
          printf("charset: 0x%x\n", f->charset);
1016
0
          if(s) printf("   name: %s\n", s);
1017
0
        }
1018
784
      }
1019
784
      break;
1020
1021
468
        case XLS_RECORD_FORMAT:
1022
468
            xlsConvertFormat((FORMAT *)buf);
1023
468
            if ((retval = xls_addFormat(pWB, (FORMAT*)buf, bof1.size)) != LIBXLS_OK) {
1024
0
                goto cleanup;
1025
0
            }
1026
468
            break;
1027
1028
980
    case XLS_RECORD_STYLE:
1029
980
      if(xls_debug) {
1030
0
        struct { unsigned short idx; unsigned char ident; unsigned char lvl; } *styl;
1031
0
        styl = (void *)buf;
1032
1033
0
        printf("    idx: 0x%x\n", styl->idx & 0x07FF);
1034
0
        if(styl->idx & 0x8000) {
1035
0
          printf("  ident: 0x%x\n", styl->ident);
1036
0
          printf("  level: 0x%x\n", styl->lvl);
1037
0
        } else {
1038
0
          char *s = get_string((char *)&buf[2], bof1.size - 2, 1, pWB);
1039
0
          printf("  name=%s\n", s);
1040
0
                    free(s);
1041
0
        }
1042
0
      }
1043
980
      break;
1044
1045
246
        case XLS_RECORD_PALETTE:
1046
246
      if(xls_debug > 10) {
1047
0
        unsigned char *p = buf + 2;
1048
0
        int idx, len;
1049
1050
0
        len = buf[0] + (buf[1] << 8);
1051
0
        for(idx=0; idx<len; ++idx) {
1052
0
          printf("   Index=0x%2.2x %2.2x%2.2x%2.2x\n", idx+8, p[0], p[1], p[2] );
1053
0
          p += 4;
1054
0
        }
1055
0
      }
1056
246
      break;
1057
1058
237
    case XLS_RECORD_1904:
1059
237
      pWB->is1904 = *(BYTE *)buf; // the field is a short, but with little endian the first byte is 0 or 1
1060
237
      if(xls_debug) {
1061
0
        printf("   mode: 0x%x\n", pWB->is1904);
1062
0
      }
1063
237
      break;
1064
1065
2
    case XLS_RECORD_FILEPASS:
1066
2
      retval = LIBXLS_ERROR_UNSUPPORTED_ENCRYPTION;
1067
2
      goto cleanup;
1068
    
1069
446
    case XLS_RECORD_DEFINEDNAME:
1070
446
      if(xls_debug) {
1071
0
        int i;
1072
0
                printf("   DEFINEDNAME: ");
1073
0
        for(i=0; i<bof1.size; ++i) printf("%2.2x ", buf[i]);
1074
0
        printf("\n");
1075
0
      }
1076
446
      break;
1077
      
1078
41.9k
        default:
1079
41.9k
      if(xls_debug)
1080
0
      {
1081
        //xls_showBOF(&bof1);
1082
0
        printf("    Not Processed in parseWorkBook():  BOF=0x%4.4X size=%d\n", bof1.id, bof1.size);
1083
0
      }
1084
41.9k
            break;
1085
79.0k
        }
1086
79.0k
        bof2=bof1;
1087
79.0k
    once=1;
1088
79.0k
    }
1089
79.0k
    while ((!pWB->olestr->eof)&&(bof1.id!=XLS_RECORD_EOF));
1090
1091
1.89k
cleanup:
1092
1.89k
    if (buf)
1093
1.87k
        free(buf);
1094
1095
1.89k
    return retval;
1096
1.89k
}
1097
1098
1099
static xls_error_t xls_preparseWorkSheet(xlsWorkSheet* pWS)
1100
22.6k
{
1101
22.6k
    if(!pWS) return LIBXLS_ERROR_NULL_ARGUMENT;
1102
1103
22.6k
    BOF tmp;
1104
22.6k
    BYTE* buf = NULL;
1105
22.6k
    xls_error_t retval = LIBXLS_OK;
1106
1107
22.6k
    verbose ("xls_preparseWorkSheet");
1108
1109
22.6k
    if (ole2_seek(pWS->workbook->olestr,pWS->filepos) == -1) {
1110
3.38k
        retval = LIBXLS_ERROR_SEEK;
1111
3.38k
        goto cleanup;
1112
3.38k
    }
1113
19.2k
    do
1114
1.80M
    {
1115
1.80M
    size_t read;
1116
1.80M
    if((read = ole2_read(&tmp, 1, 4, pWS->workbook->olestr)) != 4) {
1117
518
            if (xls_debug) fprintf(stderr, "Error: failed to read OLE size\n");
1118
518
            retval = LIBXLS_ERROR_READ;
1119
518
            goto cleanup;
1120
518
        }
1121
1.80M
        xlsConvertBof(&tmp);
1122
1.80M
        if (tmp.size) {
1123
845k
            if ((buf = realloc(buf, tmp.size)) == NULL) {
1124
0
                if (xls_debug) fprintf(stderr, "Error: failed to allocate buffer of size %d\n", (int)tmp.size);
1125
0
                retval = LIBXLS_ERROR_MALLOC;
1126
0
                goto cleanup;
1127
0
            }
1128
845k
            if((read = ole2_read(buf, 1, tmp.size, pWS->workbook->olestr)) != tmp.size) {
1129
7.39k
                if (xls_debug) fprintf(stderr, "Error: failed to read OLE block\n");
1130
7.39k
                retval = LIBXLS_ERROR_READ;
1131
7.39k
                goto cleanup;
1132
7.39k
            }
1133
845k
        }
1134
1135
1.79M
        switch (tmp.id)
1136
1.79M
        {
1137
2.41k
        case XLS_RECORD_DEFCOLWIDTH:
1138
2.41k
            if (tmp.size < sizeof(WORD)) {
1139
212
                retval = LIBXLS_ERROR_PARSE;
1140
212
                goto cleanup;
1141
212
            }
1142
2.20k
            pWS->defcolwidth = (buf[0] << 8) + (buf[1] << 16);
1143
2.20k
            break;
1144
2.47k
        case XLS_RECORD_COLINFO:
1145
2.47k
            if (tmp.size < sizeof(COLINFO)) {
1146
643
                retval = LIBXLS_ERROR_PARSE;
1147
643
                goto cleanup;
1148
643
            }
1149
1.82k
            xlsConvertColinfo((COLINFO*)buf);
1150
1.82k
            if ((retval = xls_addColinfo(pWS,(COLINFO*)buf)) != LIBXLS_OK)
1151
0
                goto cleanup;
1152
1.82k
            break;
1153
1.82k
        case XLS_RECORD_ROW:
1154
1.20k
            if (tmp.size < sizeof(ROW)) {
1155
220
                retval = LIBXLS_ERROR_PARSE;
1156
220
                goto cleanup;
1157
220
            }
1158
989
            xlsConvertRow((ROW*)buf);
1159
            /* The lcell field is 1-indexed whereas lastcol is 0-indexed */
1160
989
            if (pWS->rows.lastcol+1<((ROW*)buf)->lcell)
1161
556
                pWS->rows.lastcol=((ROW*)buf)->lcell-1;
1162
989
            if (pWS->rows.lastrow<((ROW*)buf)->index)
1163
537
                pWS->rows.lastrow=((ROW*)buf)->index;
1164
989
            break;
1165
        /* If the ROW record is incorrect or missing, infer the information from
1166
         * cell data. */
1167
2.72k
        case XLS_RECORD_MULRK:
1168
2.72k
            if (xls_isCellTooSmall(pWS->workbook, &tmp, buf)) {
1169
205
                retval = LIBXLS_ERROR_PARSE;
1170
205
                goto cleanup;
1171
205
            }
1172
2.52k
            if (pWS->rows.lastcol<xlsShortVal(((MULRK*)buf)->col) + (tmp.size - 6)/6 - 1)
1173
1.54k
                pWS->rows.lastcol=xlsShortVal(((MULRK*)buf)->col) + (tmp.size - 6)/6 - 1;
1174
2.52k
            if (pWS->rows.lastrow<xlsShortVal(((MULRK*)buf)->row))
1175
1.32k
                pWS->rows.lastrow=xlsShortVal(((MULRK*)buf)->row);
1176
2.52k
            break;
1177
3.32k
        case XLS_RECORD_MULBLANK:
1178
3.32k
            if (xls_isCellTooSmall(pWS->workbook, &tmp, buf)) {
1179
197
                retval = LIBXLS_ERROR_PARSE;
1180
197
                goto cleanup;
1181
197
            }
1182
3.12k
            if (pWS->rows.lastcol<xlsShortVal(((MULBLANK*)buf)->col) + (tmp.size - 6)/2 - 1)
1183
1.55k
                pWS->rows.lastcol=xlsShortVal(((MULBLANK*)buf)->col) + (tmp.size - 6)/2 - 1;
1184
3.12k
            if (pWS->rows.lastrow<xlsShortVal(((MULBLANK*)buf)->row))
1185
1.77k
                pWS->rows.lastrow=xlsShortVal(((MULBLANK*)buf)->row);
1186
3.12k
            break;
1187
1.04k
        case XLS_RECORD_NUMBER:
1188
2.42k
        case XLS_RECORD_RK:
1189
6.41k
        case XLS_RECORD_LABELSST:
1190
7.37k
        case XLS_RECORD_BLANK:
1191
8.51k
        case XLS_RECORD_LABEL:
1192
9.39k
        case XLS_RECORD_RSTRING:
1193
11.4k
        case XLS_RECORD_FORMULA:
1194
13.9k
        case XLS_RECORD_FORMULA_ALT:
1195
15.7k
        case XLS_RECORD_BOOLERR:
1196
15.7k
            if (xls_isCellTooSmall(pWS->workbook, &tmp, buf)) {
1197
2.17k
                retval = LIBXLS_ERROR_PARSE;
1198
2.17k
                goto cleanup;
1199
2.17k
            }
1200
13.5k
            if (pWS->rows.lastcol<xlsShortVal(((COL*)buf)->col))
1201
3.09k
                pWS->rows.lastcol=xlsShortVal(((COL*)buf)->col);
1202
13.5k
            if (pWS->rows.lastrow<xlsShortVal(((COL*)buf)->row))
1203
3.88k
                pWS->rows.lastrow=xlsShortVal(((COL*)buf)->row);
1204
13.5k
            break;
1205
1.79M
        }
1206
1.79M
        if (pWS->rows.lastcol > 255) {
1207
587
            retval = LIBXLS_ERROR_PARSE;
1208
587
            goto cleanup;
1209
587
        }
1210
1.79M
    }
1211
1.79M
    while ((!pWS->workbook->olestr->eof)&&(tmp.id!=XLS_RECORD_EOF));
1212
1213
22.6k
cleanup:
1214
22.6k
    if (buf)
1215
19.0k
        free(buf);
1216
22.6k
    return retval;
1217
19.2k
}
1218
1219
static xls_error_t xls_formatColumn(xlsWorkSheet* pWS)
1220
7.12k
{
1221
7.12k
    DWORD i,t,ii;
1222
7.12k
    DWORD fcol,lcol;
1223
7.12k
    WORD width;
1224
7.12k
    BYTE isHidden;
1225
1226
8.84k
    for (i=0;i<pWS->colinfo.count;i++)
1227
1.72k
    {
1228
1.72k
        width = pWS->colinfo.col[i].width;
1229
1.72k
        isHidden = (pWS->colinfo.col[i].flags&1);
1230
1.72k
        if (pWS->colinfo.col[i].first<=pWS->rows.lastcol)
1231
604
            fcol=pWS->colinfo.col[i].first;
1232
1.12k
        else
1233
1.12k
            fcol=pWS->rows.lastcol;
1234
1235
1.72k
        if (pWS->colinfo.col[i].last<=pWS->rows.lastcol)
1236
686
            lcol=pWS->colinfo.col[i].last;
1237
1.03k
        else
1238
1.03k
            lcol=pWS->rows.lastcol;
1239
1240
12.2M
        for (ii=0;ii<=pWS->rows.lastrow;ii++) {
1241
264M
            for (t=fcol;t<=lcol;t++) {
1242
251M
                pWS->rows.row[ii].cells.cell[t].isHidden |= isHidden;
1243
251M
                pWS->rows.row[ii].cells.cell[t].width = width;
1244
251M
            }
1245
12.2M
        }
1246
1.72k
    }
1247
7.12k
    return LIBXLS_OK;
1248
7.12k
}
1249
1250
xls_error_t xls_parseWorkSheet(xlsWorkSheet* pWS)
1251
22.6k
{
1252
22.6k
    if(!pWS) return LIBXLS_ERROR_NULL_ARGUMENT;
1253
1254
22.6k
    BOF tmp;
1255
22.6k
    BYTE* buf = NULL;
1256
22.6k
  long offset = pWS->filepos;
1257
22.6k
    size_t read;
1258
22.6k
    xls_error_t retval = 0;
1259
1260
22.6k
  struct st_cell_data *cell = NULL;
1261
22.6k
  xlsWorkBook *pWB = pWS->workbook;
1262
1263
22.6k
    verbose ("xls_parseWorkSheet");
1264
1265
22.6k
    if ((retval = xls_preparseWorkSheet(pWS)) != LIBXLS_OK) {
1266
15.5k
        goto cleanup;
1267
15.5k
    }
1268
  // printf("size=%d fatpos=%d)\n", pWS->workbook->olestr->size, pWS->workbook->olestr->fatpos);
1269
1270
7.12k
    if ((retval = xls_makeTable(pWS)) != LIBXLS_OK) {
1271
0
        goto cleanup;
1272
0
    }
1273
1274
7.12k
    if ((retval = xls_formatColumn(pWS)) != LIBXLS_OK) {
1275
0
        goto cleanup;
1276
0
    }
1277
1278
7.12k
    if (ole2_seek(pWS->workbook->olestr,pWS->filepos) == -1) {
1279
0
        retval = LIBXLS_ERROR_SEEK;
1280
0
        goto cleanup;
1281
0
    }
1282
7.12k
    do
1283
565k
    {
1284
565k
    long lastPos = offset;
1285
1286
565k
    if(xls_debug > 10) {
1287
0
      printf("LASTPOS=%ld pos=%d filePos=%d filePos=%d\n", lastPos, (int)pWB->olestr->pos, pWS->filepos, pWB->filepos);
1288
0
    }
1289
565k
    if((read = ole2_read(&tmp, 1, 4, pWS->workbook->olestr)) != 4) {
1290
0
            if (xls_debug) fprintf(stderr, "Error: failed to read OLE size\n");
1291
0
            retval = LIBXLS_ERROR_READ;
1292
0
            goto cleanup;
1293
0
        }
1294
565k
        xlsConvertBof((BOF *)&tmp);
1295
565k
        if (tmp.size) {
1296
272k
            if ((buf = realloc(buf, tmp.size)) == NULL) {
1297
0
                if (xls_debug) fprintf(stderr, "Error: failed to allocate buffer of size %d\n", (int)tmp.size);
1298
0
                retval = LIBXLS_ERROR_MALLOC;
1299
0
                goto cleanup;
1300
0
            }
1301
272k
            if((read = ole2_read(buf, 1, tmp.size, pWS->workbook->olestr)) != tmp.size) {
1302
0
                if (xls_debug) fprintf(stderr, "Error: failed to read OLE block\n");
1303
0
                retval = LIBXLS_ERROR_READ;
1304
0
                goto cleanup;
1305
0
            }
1306
272k
        }
1307
565k
    offset += 4 + tmp.size;
1308
1309
565k
    if(xls_debug)
1310
0
      xls_showBOF(&tmp);
1311
1312
565k
        switch (tmp.id)
1313
565k
        {
1314
1.73k
        case XLS_RECORD_EOF:
1315
1.73k
            break;
1316
1.89k
        case XLS_RECORD_MERGEDCELLS:
1317
1.89k
            if ((retval = xls_mergedCells(pWS,&tmp,buf)) != LIBXLS_OK) {
1318
1.35k
                goto cleanup;
1319
1.35k
            }
1320
538
            break;
1321
538
        case XLS_RECORD_ROW:
1322
463
            if (tmp.size < sizeof(ROW)) {
1323
0
                retval = LIBXLS_ERROR_PARSE;
1324
0
                goto cleanup;
1325
0
            }
1326
463
      if(xls_debug > 10) printf("ROW: %x at pos=%ld\n", tmp.id, lastPos);
1327
463
            xlsConvertRow((ROW *)buf);
1328
463
            if ((retval = xls_addRow(pWS,(ROW*)buf)) != LIBXLS_OK) {
1329
0
                goto cleanup;
1330
0
            }
1331
463
            break;
1332
704
    case XLS_RECORD_DEFCOLWIDTH:
1333
704
            if (tmp.size < sizeof(WORD)) {
1334
0
                retval = LIBXLS_ERROR_PARSE;
1335
0
                goto cleanup;
1336
0
            }
1337
704
      if(xls_debug > 10) printf("DEFAULT COL WIDTH: %d\n", ((WORD *)buf)[0]);
1338
704
      break;
1339
471
    case XLS_RECORD_DEFAULTROWHEIGHT:
1340
471
            if (tmp.size < 2 * sizeof(WORD)) {
1341
202
                retval = LIBXLS_ERROR_PARSE;
1342
202
                goto cleanup;
1343
202
            }
1344
269
      if(xls_debug > 10) printf("DEFAULT ROW Height: 0x%x %d\n", ((WORD *)buf)[0], ((WORD *)buf)[1]);
1345
269
      break;
1346
498
    case XLS_RECORD_DBCELL:
1347
498
      if(xls_debug > 10) {
1348
0
        DWORD *foo = (DWORD *)buf;
1349
0
                WORD *goo;
1350
0
        int i;
1351
0
                printf("DBCELL: size %d\n", tmp.size);
1352
0
        printf("DBCELL OFFSET=%4.4u -> ROW %ld\n", foo[0], lastPos-foo[0]);
1353
0
        ++foo;
1354
0
        goo = (WORD *)foo;
1355
0
        for(i=0; i<5; ++i) printf("goo[%d]=%4.4x %u\n", i, goo[i], goo[i]);
1356
0
      }
1357
498
      break;
1358
413
        case XLS_RECORD_INDEX:
1359
413
      if(xls_debug > 10) {
1360
0
        DWORD *foo = (DWORD *)buf;
1361
0
                int i;
1362
0
        printf("INDEX: size %d\n", tmp.size);
1363
0
        for(i=0; i<5; ++i) printf("FOO[%d]=%4.4x %u\n", i, foo[i], foo[i]);
1364
0
      }
1365
#if 0
1366
      0 4 4 4 8 4
1367
      12  4 16  4∙nm
1368
      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)
1369
      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.
1370
      Array of nm absolute stream positions to the DBCELL record (➜5.29) of each Row Block
1371
#endif
1372
413
            break;
1373
1.43k
        case XLS_RECORD_MULRK:
1374
3.32k
        case XLS_RECORD_MULBLANK:
1375
4.20k
        case XLS_RECORD_NUMBER:
1376
5.87k
        case XLS_RECORD_BOOLERR:
1377
7.22k
        case XLS_RECORD_RK:
1378
9.41k
        case XLS_RECORD_LABELSST:
1379
9.93k
        case XLS_RECORD_BLANK:
1380
10.7k
        case XLS_RECORD_LABEL:
1381
11.3k
        case XLS_RECORD_RSTRING:
1382
12.8k
        case XLS_RECORD_FORMULA:
1383
15.2k
        case XLS_RECORD_FORMULA_ALT:
1384
15.2k
            if ((cell = xls_addCell(pWS, &tmp, buf)) == NULL) {
1385
786
                retval = LIBXLS_ERROR_PARSE;
1386
786
                goto cleanup;
1387
786
            }
1388
14.4k
            break;
1389
14.4k
    case XLS_RECORD_ARRAY:
1390
683
      if(formula_handler) formula_handler(tmp.id, tmp.size, buf);
1391
683
      break;
1392
1393
3.96k
    case XLS_RECORD_STRING:
1394
3.96k
      if(cell && (cell->id == XLS_RECORD_FORMULA || cell->id == XLS_RECORD_FORMULA_ALT)) {
1395
3.39k
                xls_cell_set_str(cell, get_string((char *)buf, tmp.size,
1396
3.39k
                            (BYTE)!pWB->is5ver, pWB));
1397
3.39k
        if (xls_debug) xls_showCell(cell);
1398
3.39k
      }
1399
3.96k
      break;
1400
1401
539k
        default:
1402
539k
      if(xls_debug)
1403
0
      {
1404
        //xls_showBOF(&tmp);
1405
0
                if (tmp.size >= sizeof(COL)) {
1406
0
                    printf("   [%d:%d]: 0x%X at pos=%lu size=%u\n", xlsShortVal(((COL*)buf)->row), xlsShortVal(((COL*)buf)->col),
1407
0
                            tmp.id, lastPos, tmp.size);
1408
0
                } else {
1409
0
                    printf("   0x%X at pos=%lu size=%u\n", tmp.id, lastPos, tmp.size);
1410
0
                }
1411
0
      }
1412
539k
            break;
1413
565k
        }
1414
565k
    }
1415
563k
    while ((!pWS->workbook->olestr->eof)&&(tmp.id!=XLS_RECORD_EOF));
1416
1417
22.6k
cleanup:
1418
22.6k
    if (buf)
1419
7.09k
        free(buf);
1420
1421
22.6k
    return retval;
1422
7.12k
}
1423
1424
xlsWorkSheet * xls_getWorkSheet(xlsWorkBook* pWB,int num)
1425
22.6k
{
1426
22.6k
    xlsWorkSheet * pWS = NULL;
1427
22.6k
    verbose ("xls_getWorkSheet");
1428
22.6k
    if (num >= 0 && num < (int)pWB->sheets.count) {
1429
22.6k
        pWS = calloc(1, sizeof(xlsWorkSheet));
1430
22.6k
        pWS->filepos=pWB->sheets.sheet[num].filepos;
1431
22.6k
        pWS->workbook=pWB;
1432
22.6k
        pWS->rows.lastcol=0;
1433
22.6k
        pWS->rows.lastrow=0;
1434
22.6k
        pWS->colinfo.count=0;
1435
22.6k
    }
1436
22.6k
    return pWS;
1437
22.6k
}
1438
1439
2.18k
static xlsWorkBook *xls_open_ole(OLE2 *ole, const char *charset, xls_error_t *outError) {
1440
2.18k
    xlsWorkBook* pWB;
1441
2.18k
    xls_error_t retval = LIBXLS_OK;
1442
1443
2.18k
    pWB = calloc(1, sizeof(xlsWorkBook));
1444
2.18k
    verbose ("xls_open_ole");
1445
1446
2.18k
    if ((pWB->olestr=ole2_fopen(ole, "\005SummaryInformation")))
1447
23
    {
1448
23
        pWB->summary = calloc(1,4096);
1449
23
    if (ole2_read(pWB->summary, 4096, 1, pWB->olestr) == -1) {
1450
2
            if (xls_debug) fprintf(stderr, "SummaryInformation not found\n");
1451
2
            retval = LIBXLS_ERROR_READ;
1452
2
            goto cleanup;
1453
2
        }
1454
21
    ole2_fclose(pWB->olestr);
1455
21
  }
1456
1457
2.18k
    if ((pWB->olestr=ole2_fopen(ole, "\005DocumentSummaryInformation")))
1458
16
    {
1459
16
        pWB->docSummary = calloc(1, 4096);
1460
16
    if (ole2_read(pWB->docSummary, 4096, 1, pWB->olestr) == -1) {
1461
1
            if (xls_debug) fprintf(stderr, "DocumentSummaryInformation not found\n");
1462
1
            retval = LIBXLS_ERROR_READ;
1463
1
            goto cleanup;
1464
1
        }
1465
15
    ole2_fclose(pWB->olestr);
1466
15
  }
1467
1468
#if 0
1469
  if(xls_debug) {
1470
    printf("summary=%d docsummary=%d\n", pWB->summary ? 1 : 0, pWB->docSummary ? 1 : 0);
1471
    xlsSummaryInfo *si = xls_summaryInfo(pWB);
1472
    printf("title=%s\n", si->title);
1473
    printf("subject=%s\n", si->subject);
1474
    printf("author=%s\n", si->author);
1475
    printf("keywords=%s\n", si->keywords);
1476
    printf("comment=%s\n", si->comment);
1477
    printf("lastAuthor=%s\n", si->lastAuthor);
1478
    printf("appName=%s\n", si->appName);
1479
    printf("category=%s\n", si->category);
1480
    printf("manager=%s\n", si->manager);
1481
    printf("company=%s\n", si->company);
1482
  }
1483
#endif
1484
1485
    // open Workbook
1486
2.18k
    if (!(pWB->olestr=ole2_fopen(ole,"Workbook")) && !(pWB->olestr=ole2_fopen(ole,"Book")))
1487
289
    {
1488
289
        if(xls_debug) fprintf(stderr, "Workbook not found\n");
1489
289
        retval = LIBXLS_ERROR_PARSE;
1490
289
        goto cleanup;
1491
289
    }
1492
1493
1.89k
    pWB->sheets.count=0;
1494
1.89k
    pWB->xfs.count=0;
1495
1.89k
    pWB->fonts.count=0;
1496
1.89k
    pWB->charset = strdup(charset ? charset : "UTF-8");
1497
1498
1.89k
    retval = xls_parseWorkBook(pWB);
1499
1500
2.18k
cleanup:
1501
2.18k
    if (retval != LIBXLS_OK) {
1502
805
        if (!pWB->olestr)
1503
289
            ole2_close(ole);
1504
805
        xls_close_WB(pWB);
1505
805
        pWB = NULL;
1506
805
    }
1507
2.18k
    if (outError)
1508
0
        *outError = retval;
1509
1510
2.18k
    return pWB;
1511
1.89k
}
1512
1513
xlsWorkBook* xls_open(const char *file, const char* charset)
1514
0
{
1515
0
    return xls_open_file(file, charset, NULL);
1516
0
}
1517
1518
0
xlsWorkBook* xls_open_file(const char *file, const char* charset, xls_error_t *outError) {
1519
0
    OLE2* ole = NULL;
1520
1521
0
    if (!(ole=ole2_open_file(file)))
1522
0
    {
1523
0
        if (xls_debug) fprintf(stderr, "File \"%s\" not found\n",file);
1524
0
        if (outError) *outError = LIBXLS_ERROR_OPEN;
1525
0
        return NULL;
1526
0
    }
1527
1528
0
    return xls_open_ole(ole, charset, outError);
1529
0
}
1530
1531
xlsWorkBook *xls_open_buffer(const unsigned char *buffer, size_t len,
1532
3.36k
        const char *charset, xls_error_t *outError) {
1533
3.36k
    OLE2* ole = NULL;
1534
1535
3.36k
    if (!(ole=ole2_open_buffer(buffer, len)))
1536
1.18k
    {
1537
1.18k
        if (outError) *outError = LIBXLS_ERROR_OPEN;
1538
1.18k
        return NULL;
1539
1.18k
    }
1540
1541
2.18k
    return xls_open_ole(ole, charset, outError);
1542
3.36k
}
1543
1544
xlsRow *xls_row(xlsWorkSheet* pWS, WORD cellRow)
1545
0
{
1546
0
    if(cellRow > pWS->rows.lastrow)
1547
0
        return NULL;
1548
1549
0
    if (pWS->rows.row == NULL)
1550
0
        return NULL;
1551
1552
0
    return &pWS->rows.row[cellRow];
1553
0
}
1554
1555
xlsCell *xls_cell(xlsWorkSheet* pWS, WORD cellRow, WORD cellCol)
1556
0
{
1557
0
    struct st_row_data  *row;
1558
1559
0
    if ((row = xls_row(pWS, cellRow)) == NULL)
1560
0
        return NULL;
1561
1562
0
    if(cellCol >= row->cells.count)
1563
0
        return NULL;
1564
1565
0
    return &row->cells.cell[cellCol];
1566
0
}
1567
1568
void xls_close_WB(xlsWorkBook* pWB)
1569
2.18k
{
1570
2.18k
  OLE2*   ole;
1571
1572
2.18k
  verbose ("xls_close");
1573
1574
2.18k
  if(!pWB) return;
1575
1576
    // OLE first
1577
2.18k
    if (pWB->olestr) {
1578
1.89k
        ole=pWB->olestr->ole;
1579
1.89k
        ole2_fclose(pWB->olestr);
1580
1.89k
        ole2_close(ole);
1581
1.89k
    }
1582
1583
    // WorkBook
1584
2.18k
    free(pWB->charset);
1585
1586
    // Sheets
1587
2.18k
    {
1588
2.18k
        DWORD i;
1589
25.3k
        for(i=0; i<pWB->sheets.count; ++i) {
1590
23.1k
            free(pWB->sheets.sheet[i].name);
1591
23.1k
        }
1592
2.18k
        free(pWB->sheets.sheet);
1593
2.18k
    }
1594
1595
    // SST
1596
2.18k
    {
1597
2.18k
        DWORD i;
1598
3.96G
        for(i=0; i<pWB->sst.count; ++i) {
1599
3.96G
            free(pWB->sst.string[i].str);
1600
3.96G
        }
1601
2.18k
        free(pWB->sst.string);
1602
2.18k
    }
1603
1604
    // xfs
1605
2.18k
    {
1606
2.18k
        free(pWB->xfs.xf);
1607
2.18k
    }
1608
1609
    // fonts
1610
2.18k
    {
1611
2.18k
        DWORD i;
1612
2.96k
        for(i=0; i<pWB->fonts.count; ++i) {
1613
784
            free(pWB->fonts.font[i].name);
1614
784
        }
1615
2.18k
        free(pWB->fonts.font);
1616
2.18k
    }
1617
1618
    // formats
1619
2.18k
    {
1620
2.18k
        DWORD i;
1621
2.65k
        for(i=0; i<pWB->formats.count; ++i) {
1622
468
            free(pWB->formats.format[i].value);
1623
468
        }
1624
2.18k
        free(pWB->formats.format);
1625
2.18k
    }
1626
1627
    // buffers
1628
2.18k
  if(pWB->summary)  free(pWB->summary);
1629
2.18k
  if(pWB->docSummary) free(pWB->docSummary);
1630
1631
2.18k
#ifdef HAVE_ICONV
1632
2.18k
    if (pWB->converter)
1633
97
        iconv_close((iconv_t)pWB->converter);
1634
2.18k
    if (pWB->utf16_converter)
1635
404
        iconv_close((iconv_t)pWB->utf16_converter);
1636
2.18k
#endif
1637
1638
2.18k
    if (pWB->utf8_locale)
1639
0
        xls_freelocale((xls_locale_t)pWB->utf8_locale);
1640
1641
    // TODO - free other dynamically allocated objects like string table??
1642
2.18k
    free(pWB);
1643
2.18k
}
1644
1645
void xls_close_WS(xlsWorkSheet* pWS)
1646
22.6k
{
1647
22.6k
  if(!pWS) return;
1648
1649
22.6k
    if (pWS->rows.row) {
1650
7.12k
        DWORD i, j;
1651
75.2M
        for(j=0; j<=pWS->rows.lastrow; ++j) {
1652
75.2M
            struct st_row_data *row = &pWS->rows.row[j];
1653
7.15G
            for(i=0; i<row->cells.count; ++i) {
1654
7.07G
                free(row->cells.cell[i].str);
1655
7.07G
            }
1656
75.2M
            free(row->cells.cell);
1657
75.2M
        }
1658
7.12k
        free(pWS->rows.row);
1659
7.12k
    }
1660
1661
    // COLINFO
1662
22.6k
    {
1663
22.6k
        free(pWS->colinfo.col);
1664
22.6k
    }
1665
22.6k
    free(pWS);
1666
22.6k
}
1667
1668
const char* xls_getVersion(void)
1669
0
{
1670
0
    return PACKAGE_VERSION;
1671
0
}
1672
1673
0
const char* xls_getError(xls_error_t code) {
1674
0
    if (code == LIBXLS_OK)
1675
0
        return "No error";
1676
0
    if (code == LIBXLS_ERROR_READ)
1677
0
        return "Unable to read from file";
1678
0
    if (code == LIBXLS_ERROR_OPEN)
1679
0
        return "Unable to open file";
1680
0
    if (code == LIBXLS_ERROR_SEEK)
1681
0
        return "Unable to seek within file";
1682
0
    if (code == LIBXLS_ERROR_MALLOC)
1683
0
        return "Unable to allocate memory";
1684
0
    if (code == LIBXLS_ERROR_PARSE)
1685
0
        return "Unable to parse file";
1686
0
    if (code == LIBXLS_ERROR_UNSUPPORTED_ENCRYPTION)
1687
0
        return "Unsupported encryption scheme";
1688
1689
0
    return "Unknown error";
1690
0
}
1691
1692
//
1693
// http://poi.apache.org/hpsf/internals.html
1694
// or google "DocumentSummaryInformation and UserDefined Property Sets" and look for MSDN hits
1695
//
1696
1697
xlsSummaryInfo *xls_summaryInfo(xlsWorkBook* pWB)
1698
0
{
1699
0
  xlsSummaryInfo  *pSI;
1700
1701
0
  pSI = (xlsSummaryInfo *)calloc(1, sizeof(xlsSummaryInfo));
1702
0
  xls_dumpSummary(pWB->summary, 1, pSI);
1703
0
  xls_dumpSummary(pWB->docSummary, 0, pSI);
1704
1705
0
  return pSI;
1706
0
}
1707
1708
void xls_close_summaryInfo(xlsSummaryInfo *pSI)
1709
0
{
1710
0
  if(!pSI) return;
1711
1712
0
  if(pSI->title)   free(pSI->title);
1713
0
  if(pSI->subject) free(pSI->subject);
1714
0
  if(pSI->author)   free(pSI->author);
1715
0
  if(pSI->keywords) free(pSI->keywords);
1716
0
  if(pSI->comment) free(pSI->comment);
1717
0
  if(pSI->lastAuthor) free(pSI->lastAuthor);
1718
0
  if(pSI->appName) free(pSI->appName);
1719
0
  if(pSI->category) free(pSI->category);
1720
0
  if(pSI->manager) free(pSI->manager);
1721
0
  if(pSI->company) free(pSI->company);
1722
1723
0
  free(pSI);
1724
0
}
1725
1726
0
static void xls_dumpSummary(char *buf,int isSummary,xlsSummaryInfo *pSI) {
1727
0
  header      *head;
1728
0
  sectionList   *secList;
1729
0
  propertyList  *plist;
1730
0
  sectionHeader *secHead;
1731
0
  property    *prop;
1732
0
  uint32_t i, j;
1733
1734
0
  if(!buf) return; // perhaps the document was missing??
1735
1736
0
  head = (header *)buf;
1737
  //printf("header: \n");
1738
  //printf("  sig=%x\n", head->sig);
1739
  //printf("  os=%x\n", head->os >> 16);
1740
  //printf("  class=%8.8x%8.8x%8.8x%8.8x\n", head->format[0], head->format[1], head->format[2], head->format[3]);
1741
  //printf("  count=%x\n", head->count);
1742
1743
0
  for(i=0; i<head->count; ++i) {
1744
0
    secList = &head->secList[i];
1745
    //printf("Section %d:\n", i);
1746
    //printf("  class=%8.8x%8.8x%8.8x%8.8x\n", secList->format[0], secList->format[1], secList->format[2], secList->format[3]);
1747
    //printf("  offset=%d (now at %ld\n", secList->offset, (char *)secList - (char *)buf + sizeof(sectionList));
1748
1749
1750
0
    secHead = (sectionHeader *)((char *)head + secList->offset);
1751
    //printf("  len=%d\n", secHead->length);
1752
    //printf("  properties=%d\n", secHead->numProperties);
1753
0
    for(j=0; j<secHead->numProperties; ++j) {
1754
0
      BYTE **s;
1755
1756
0
      plist = &secHead->properties[j];
1757
      //printf("      ---------\n");
1758
      //printf("      propID=%d offset=%d\n", plist->propertyID, plist->sectionOffset);
1759
0
      prop = (property *)((char *)secHead + plist->sectionOffset);
1760
      //printf("      propType=%d\n", prop->propertyID);
1761
1762
0
      switch(prop->propertyID) {
1763
0
      case 2:
1764
        //printf("      xlsShortVal=%x\n", *(uint16_t *)prop->data);
1765
0
        break;
1766
0
      case 3:
1767
        //printf("      wordVal=%x\n", *(uint32_t *)prop->data);
1768
0
        break;
1769
0
      case 30:
1770
        //printf("      longVal=%llx\n", *(uint64_t *)prop->data);
1771
        //printf("      s[%u]=%s\n", *(uint32_t  *)prop->data, (char *)prop->data + 4);
1772
0
        if(isSummary) {
1773
0
          switch(plist->propertyID) {
1774
0
          case 2:   s = &pSI->title;    break;
1775
0
          case 3:   s = &pSI->subject;    break;
1776
0
          case 4:   s = &pSI->author;   break;
1777
0
          case 5:   s = &pSI->keywords;   break;
1778
0
          case 6:   s = &pSI->comment;    break;
1779
0
          case 8:   s = &pSI->lastAuthor; break;
1780
0
          case 18:  s = &pSI->appName;    break;
1781
0
          default:  s = NULL;       break;
1782
0
          }
1783
0
        } else {
1784
0
          switch(plist->propertyID) {
1785
0
          case 2:   s = &pSI->category;   break;
1786
0
          case 14:  s = &pSI->manager;    break;
1787
0
          case 15:  s = &pSI->company;    break;
1788
0
          default:  s = NULL;       break;
1789
0
          }
1790
0
        }
1791
0
        if(s) *s = (BYTE *)strdup((char *)prop->data + 4);
1792
0
        break;
1793
0
      case 64:
1794
        //printf("      longVal=%llx\n", *(uint64_t *)prop->data);
1795
0
        break;
1796
0
      case 65:
1797
#if 0
1798
        {
1799
        uint32_t k;
1800
        for(k=0; k<*(uint32_t  *)prop->data; ++k) {
1801
        unsigned char *t = (unsigned char *)prop->data + 4 + k;
1802
        printf(" %2.2x(%c)", *t, *t);
1803
        }
1804
        printf("\n");
1805
        }
1806
#endif
1807
0
        break;
1808
0
      default:
1809
        //printf("      UNKNOWN!\n");
1810
0
        break;
1811
0
      }
1812
0
    }
1813
0
  }
1814
0
}
1815
1816
void xls_set_formula_hander(xls_formula_handler handler)
1817
0
{
1818
0
  formula_handler = handler;
1819
0
}