[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#920804: release.debian.org: security upload for r-cran-readxl



Package: release.debian.org
Severity: normal

This is a follow-up to the discussion in #919324 and subsequent emails with
Moritz and Salvatore. The two CVEs are genuine and fixed, the issue however
is no a full-blown denial-of-service etc so Moritz suggested a normal
security upload.

The debdiff is included below, with the distribution changed from
stretch-security to just stretch.

Happy to upload once you give a green light.  (System information remove as I
type this on Ubuntu 18.10 ...)

Dirk

diff -Nru r-cran-readxl-0.1.1/debian/changelog r-cran-readxl-0.1.1/debian/changelog
--- r-cran-readxl-0.1.1/debian/changelog	2018-04-13 08:18:46.000000000 -0500
+++ r-cran-readxl-0.1.1/debian/changelog	2019-01-27 09:29:50.000000000 -0600
@@ -1,3 +1,18 @@
+r-cran-readxl (0.1.1-1+deb9u2) stretch; urgency=high
+
+  * src/libxls/ole.h: Updated from readxl upstream (Closes: #919324)
+  * libxls/xlstool.h: Idem
+  * ole.c: Idem
+  * xls.c: Idem
+  * xlstool.c: Idem
+
+  * This addresses
+        CVE-2018-20450
+        CVE-2018-20452
+    with corresponding upstream patch in libxls and readxl
+
+ -- Dirk Eddelbuettel <edd@debian.org>  Sun, 27 Jan 2019 09:29:50 -0600
+
 r-cran-readxl (0.1.1-1+deb9u1) stretch-security; urgency=high
 
   * src/endian.c: Updated from libxls upstream (Closes: #895564)
diff -Nru r-cran-readxl-0.1.1/debian/patches/series r-cran-readxl-0.1.1/debian/patches/series
--- r-cran-readxl-0.1.1/debian/patches/series	2018-04-13 08:18:46.000000000 -0500
+++ r-cran-readxl-0.1.1/debian/patches/series	2019-01-27 09:29:50.000000000 -0600
@@ -1 +1,2 @@
 libxls_upstream
+updated-upstream-changes
diff -Nru r-cran-readxl-0.1.1/debian/patches/updated-upstream-changes r-cran-readxl-0.1.1/debian/patches/updated-upstream-changes
--- r-cran-readxl-0.1.1/debian/patches/updated-upstream-changes	1969-12-31 18:00:00.000000000 -0600
+++ r-cran-readxl-0.1.1/debian/patches/updated-upstream-changes	2019-01-27 09:29:50.000000000 -0600
@@ -0,0 +1,2699 @@
+Description: Updated upstream changes
+ Bug report #919324 contains two CVE reports against libxls which are, along
+ with two more listed at the upstream GitHub repo, fixed in this version of
+ readxl via updated files from libxls.
+Author: Dirk Eddelbuettel <edd@debian.org>
+Bug-Debian: https://bugs.debian.org/919324
+
+---
+Origin: upstream, https://github.com/evanmiller/libxls, various
+Bug: https://bugs.debian.org/919324
+Forwarded: not-needed
+Last-Update: 2019-01-27
+
+--- r-cran-readxl-0.1.1.orig/src/libxls/ole.h
++++ r-cran-readxl-0.1.1/src/libxls/ole.h
+@@ -1,33 +1,36 @@
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  *
+- * This file is part of libxls -- A multiplatform, C/C++ library
+- * for parsing Excel(TM) files.
++ * Copyright 2004 Komarov Valery
++ * Copyright 2006 Christophe Leitienne
++ * Copyright 2008-2017 David Hoerl
++ * Copyright 2013 Bob Colbert
++ * Copyright 2013-2018 Evan Miller
+  *
+- * Redistribution and use in source and binary forms, with or without modification, are
+- * permitted provided that the following conditions are met:
++ * This file is part of libxls -- A multiplatform, C/C++ library for parsing
++ * Excel(TM) files.
+  *
+- *    1. Redistributions of source code must retain the above copyright notice, this list of
+- *       conditions and the following disclaimer.
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+  *
+- *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+- *       of conditions and the following disclaimer in the documentation and/or other materials
+- *       provided with the distribution.
+- *
+- * THIS SOFTWARE IS PROVIDED BY David Hoerl ''AS IS'' AND ANY EXPRESS OR IMPLIED
+- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David Hoerl OR
+- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
++ *    1. Redistributions of source code must retain the above copyright notice,
++ *    this list of conditions and the following disclaimer.
++ *
++ *    2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS
++ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+- * Copyright 2004 Komarov Valery
+- * Copyright 2006 Christophe Leitienne
+- * Copyright 2013 Bob Colbert
+- * Copyright 2008-2013 David Hoerl
+- *
+  */
+ 
+ #ifndef OLE_INCLUDE
+@@ -37,7 +40,7 @@
+ 
+ #include "libxls/xlstypes.h"
+ 
+-#ifdef AIX
++#if defined(_AIX) || defined(__sun)
+ #pragma pack(1)
+ #else
+ #pragma pack(push, 1)
+@@ -140,7 +143,7 @@ typedef struct OLE2Stream
+ }
+ OLE2Stream;
+ 
+-#ifdef AIX
++#if defined(_AIX) || defined(__sun)
+ #pragma pack(1)
+ #else
+ #pragma pack(push, 1)
+--- r-cran-readxl-0.1.1.orig/src/libxls/xlstool.h
++++ r-cran-readxl-0.1.1/src/libxls/xlstool.h
+@@ -1,36 +1,41 @@
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  *
+- * This file is part of libxls -- A multiplatform, C/C++ library
+- * for parsing Excel(TM) files.
++ * Copyright 2004 Komarov Valery
++ * Copyright 2006 Christophe Leitienne
++ * Copyright 2008-2017 David Hoerl
++ * Copyright 2013 Bob Colbert
++ * Copyright 2013-2018 Evan Miller
+  *
+- * Redistribution and use in source and binary forms, with or without modification, are
+- * permitted provided that the following conditions are met:
++ * This file is part of libxls -- A multiplatform, C/C++ library for parsing
++ * Excel(TM) files.
+  *
+- *    1. Redistributions of source code must retain the above copyright notice, this list of
+- *       conditions and the following disclaimer.
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+  *
+- *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+- *       of conditions and the following disclaimer in the documentation and/or other materials
+- *       provided with the distribution.
+- *
+- * THIS SOFTWARE IS PROVIDED BY David Hoerl ''AS IS'' AND ANY EXPRESS OR IMPLIED
+- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David Hoerl OR
+- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
++ *    1. Redistributions of source code must retain the above copyright notice,
++ *    this list of conditions and the following disclaimer.
++ *
++ *    2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS
++ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+- * Copyright 2004 Komarov Valery
+- * Copyright 2006 Christophe Leitienne
+- * Copyright 2013 Bob Colbert
+- * Copyright 2008-2013 David Hoerl
+- *
+  */
+ 
+ #include "libxls/xlsstruct.h"
++/* Mask illegal functions for CMD check */
++#include "cran.h"
+ 
+ extern void dumpbuf(BYTE* fname,long size,BYTE* buf);
+ extern void verbose(char* str);
+@@ -47,6 +52,6 @@ extern void xls_showCell(struct st_cell_
+ extern void xls_showFont(struct st_font_data* font);
+ extern void xls_showXF(XF8* xf);
+ extern void xls_showFormat(struct st_format_data* format);
+-extern char* xls_getfcell(xlsWorkBook* pWB, struct st_cell_data* cell, WORD *label);
++extern char* xls_getfcell(xlsWorkBook* pWB, struct st_cell_data* cell, BYTE *label);
+ extern char* xls_getCSS(xlsWorkBook* pWB);
+ extern void xls_showBOF(BOF* bof);
+--- r-cran-readxl-0.1.1.orig/src/ole.c
++++ r-cran-readxl-0.1.1/src/ole.c
+@@ -1,32 +1,35 @@
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  *
+- * This file is part of libxls -- A multiplatform, C/C++ library
+- * for parsing Excel(TM) files.
++ * Copyright 2004 Komarov Valery
++ * Copyright 2006 Christophe Leitienne
++ * Copyright 2008-2017 David Hoerl
++ * Copyright 2013 Bob Colbert
++ * Copyright 2013-2018 Evan Miller
+  *
+- * Redistribution and use in source and binary forms, with or without modification, are
+- * permitted provided that the following conditions are met:
++ * This file is part of libxls -- A multiplatform, C/C++ library for parsing
++ * Excel(TM) files.
+  *
+- *    1. Redistributions of source code must retain the above copyright notice, this list of
+- *       conditions and the following disclaimer.
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+  *
+- *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+- *       of conditions and the following disclaimer in the documentation and/or other materials
+- *       provided with the distribution.
++ *    1. Redistributions of source code must retain the above copyright notice,
++ *    this list of conditions and the following disclaimer.
+  *
+- * THIS SOFTWARE IS PROVIDED BY David Hoerl ''AS IS'' AND ANY EXPRESS OR IMPLIED
+- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David Hoerl OR
+- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *    2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
+  *
+- * Copyright 2004 Komarov Valery
+- * Copyright 2006 Christophe Leitienne
+- * Copyright 2013 Bob Colbert
+- * Copyright 2008-2013 David Hoerl
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS
++ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  */
+ 
+@@ -41,6 +44,8 @@
+ #include "libxls/ole.h"
+ #include "libxls/xlstool.h"
+ #include "libxls/endian.h"
++/* Mask illegal functions for CMD check */
++#include "cran.h"
+ 
+ extern int xls_debug;
+ 
+@@ -51,10 +56,11 @@ extern int xls_debug;
+ static const DWORD ENDOFCHAIN	= 0xFFFFFFFE;	// -2
+ static const DWORD FREESECT		= 0xFFFFFFFF;	// -1
+ 
+-static size_t sector_pos(OLE2* ole2, size_t sid);
+-static ssize_t sector_read(OLE2* ole2, void *buffer, size_t sid);
++static size_t sector_pos(OLE2* ole2, DWORD sid);
++static ssize_t sector_read(OLE2* ole2, void *buffer, size_t buffer_len, DWORD sid);
+ static ssize_t read_MSAT(OLE2* ole2, OLE2Header *oleh);
+ static void *ole_malloc(size_t len);
++static void *ole_realloc(void *ptr, size_t len);
+ 
+ static void *ole_malloc(size_t len) {
+     if (len > (1<<24) || len == 0) {
+@@ -63,6 +69,45 @@ static void *ole_malloc(size_t len) {
+     return malloc(len);
+ }
+ 
++static void *ole_realloc(void *ptr, size_t len) {
++    if (len > (1<<24) || len == 0) {
++        free(ptr);
++        return NULL;
++    }
++    return realloc(ptr, len);
++}
++
++int ole2_validate_chain(OLE2 *ole) {
++    DWORD count = 0;
++    DWORD sector = ole->dirstart;
++    while (sector != ENDOFCHAIN) {
++        if (sector >= ole->SecIDCount)
++            return 0;
++        
++        if (++count >= ole->SecIDCount)
++            return 0;
++
++        sector = xlsIntVal(ole->SecID[sector]);
++    }
++    return 1;
++}
++
++int ole2_validate_sector(DWORD sector, OLE2 *ole) {
++    if (sector >= ole->SecIDCount) {
++        if (xls_debug) fprintf(stderr, "Error: fatpos %d out-of-bounds for SecID[%d]\n",
++                (int)sector, ole->SecIDCount);
++        return 0;
++    }
++
++    if (sector == xlsIntVal(ole->SecID[sector])) {
++        if (xls_debug) fprintf(stderr, "Error: Sector loop detected, SecID[%d] = %d\n",
++                (int)sector, (int)sector);
++        return 0;
++    }
++
++    return 1;
++}
++
+ // Read next sector of stream
+ int ole2_bufread(OLE2Stream* olest) 
+ {
+@@ -96,18 +141,16 @@ int ole2_bufread(OLE2Stream* olest)
+ 			olest->cfat++;
+ 		} else {
+ 			if ((int)olest->fatpos < 0 ||
+-                sector_read(olest->ole, olest->buf, olest->fatpos) == -1) {
++                sector_read(olest->ole, olest->buf, olest->bufsize, olest->fatpos) == -1) {
+                 if (xls_debug) fprintf(stderr, "Error: Unable to read sector #%d\n", (int)olest->fatpos);
+                 return -1;
+             }
+ 
+-            if (olest->fatpos >= olest->ole->SecIDCount) {
+-                if (xls_debug) fprintf(stderr, "Error: fatpos %d out-of-bounds for SecID[%d]\n",
+-                        (int)olest->fatpos, olest->ole->SecIDCount);
++            if (!ole2_validate_sector(olest->fatpos, olest->ole)) {
+                 return -1;
+             }
+ 
+-			olest->fatpos=xlsIntVal(olest->ole->SecID[olest->fatpos]);
++            olest->fatpos = xlsIntVal(olest->ole->SecID[olest->fatpos]);
+ 			olest->pos=0;
+ 			olest->cfat++;
+ 		}
+@@ -121,7 +164,6 @@ ssize_t ole2_read(void* buf, size_t size
+ {
+     size_t didReadCount=0;
+     size_t totalReadCount;
+-	size_t needToReadCount;
+ 
+ 	totalReadCount=size*count;
+ 
+@@ -142,32 +184,25 @@ ssize_t ole2_read(void* buf, size_t size
+ 	while ((!olest->eof) && (didReadCount < totalReadCount))
+ 	{
+ 		unsigned long remainingBytes;
++        size_t needToReadCount;
+ 
+ 		needToReadCount	= totalReadCount - didReadCount;
+ 		remainingBytes	= olest->bufsize - olest->pos;
+-		//printf("  test: (totalReadCount-didReadCount)=%d (olest->bufsize-olest->pos)=%d\n", (totalReadCount-didReadCount), (olest->bufsize-olest->pos) );
+ 
+-		if (needToReadCount < remainingBytes)	// does the current sector contain all the data I need?
+-		{
+-			// printf("  had %d bytes of memory, copy=%d\n", (olest->bufsize-olest->pos), needToReadCount);
++		if (needToReadCount < remainingBytes) { // does the current sector contain all the data I need?
+ 			memcpy((BYTE*)buf + didReadCount, olest->buf + olest->pos, needToReadCount);
+ 			olest->pos		+= needToReadCount;
+ 			didReadCount	+= needToReadCount;
+ 		} else {
+-			// printf("  had %d bytes of memory, copy=%d\n", remainingBytes, remainingBytes);
+ 			memcpy((BYTE*)buf + didReadCount, olest->buf + olest->pos, remainingBytes);
+ 			olest->pos		+= remainingBytes;
+ 			didReadCount	+= remainingBytes;
+ 			if (ole2_bufread(olest) == -1)
+                 return -1;
+ 		}
+-		//printf("  if(fatpos=0x%X==EOC=0x%X) && (pos=%d >= bufsize=%d)\n", olest->fatpos, ENDOFCHAIN, olest->pos, olest->bufsize);
+-		if (((DWORD)olest->fatpos == ENDOFCHAIN) && (olest->pos >= olest->bufsize))
+-		{
++		if (((DWORD)olest->fatpos == ENDOFCHAIN) && (olest->pos >= olest->bufsize)) {
+ 			olest->eof=1;
+ 		}
+-
+-		//printf("  eof=%d (didReadCount=%ld != totalReadCount=%ld)\n", olest->eof, didReadCount, totalReadCount);
+ 	}
+     if (didReadCount > totalReadCount)
+         return -1;
+@@ -200,13 +235,11 @@ OLE2Stream* ole2_sopen(OLE2* ole,DWORD s
+     fprintf(stderr, "ole2_sopen start=%Xh\n", start);
+ #endif
+ 
+-	olest=(OLE2Stream*)calloc(1, sizeof(OLE2Stream));
++	olest = calloc(1, sizeof(OLE2Stream));
+ 	olest->ole=ole;
+ 	olest->size=size;
+ 	olest->fatpos=start;
+ 	olest->start=start;
+-	olest->pos=0;
+-	olest->eof=0;
+ 	olest->cfat=-1;
+ 	if((long)size > 0 && size < (size_t)ole->sectorcutoff) {
+ 		olest->bufsize=ole->lssector;
+@@ -214,8 +247,12 @@ OLE2Stream* ole2_sopen(OLE2* ole,DWORD s
+ 	} else {
+ 		olest->bufsize=ole->lsector;
+ 	}
+-	olest->buf = ole_malloc(olest->bufsize);
+-	ole2_bufread(olest);
++    olest->buf = ole_malloc(olest->bufsize);
++
++    if (ole2_bufread(olest) == -1) {
++        ole2_fclose(olest);
++        olest = NULL;
++    }
+ 
+ 	// if(xls_debug) printf("sopen: sector=%d next=%d\n", start, olest->fatpos);
+     return olest;
+@@ -232,19 +269,21 @@ int ole2_seek(OLE2Stream* olest,DWORD of
+ 		int i;
+ 		olest->fatpos=olest->start;
+ 
+-		if (div_rez.quot!=0)
+-		{
+-			for (i=0;i<div_rez.quot;i++) {
++        if (div_rez.quot!=0)
++        {
++            for (i=0;i<div_rez.quot;i++) {
+                 if (olest->fatpos >= olest->ole->SSecIDCount)
+                     return -1;
+-				olest->fatpos=xlsIntVal(olest->ole->SSecID[olest->fatpos]);
++                olest->fatpos=xlsIntVal(olest->ole->SSecID[olest->fatpos]);
+             }
+-		}
++        }
+ 
+-		ole2_bufread(olest);
+-		olest->pos=div_rez.rem;
+-		olest->eof=0;
+-		olest->cfat=div_rez.quot;
++        if (ole2_bufread(olest) == -1)
++            return -1;
++
++        olest->pos=div_rez.rem;
++        olest->eof=0;
++        olest->cfat=div_rez.quot;
+ 		//printf("%i=%i %i\n",ofs,div_rez.quot,div_rez.rem);
+ 	} else {
+ 		ldiv_t div_rez=ldiv(ofs,olest->ole->lsector);
+@@ -254,16 +293,18 @@ int ole2_seek(OLE2Stream* olest,DWORD of
+ #endif
+ 		olest->fatpos=olest->start;
+ 
+-		if (div_rez.quot!=0)
+-		{
+-			for (i=0;i<div_rez.quot;i++) {
+-                if (olest->fatpos >= olest->ole->SecIDCount)
++        if (div_rez.quot!=0)
++        {
++            for (i=0;i<div_rez.quot;i++) {
++                if (!ole2_validate_sector(olest->fatpos, olest->ole))
+                     return -1;
+                 olest->fatpos=xlsIntVal(olest->ole->SecID[olest->fatpos]);
+             }
+-		}
++        }
++
++        if (ole2_bufread(olest) == -1)
++            return -1;
+ 
+-		ole2_bufread(olest);
+ 		olest->pos=div_rez.rem;
+ 		olest->eof=0;
+ 		olest->cfat=div_rez.quot;
+@@ -296,7 +337,7 @@ OLE2Stream*  ole2_fopen(OLE2* ole, const
+     return NULL;
+ }
+ 
+-int ole2_fseek(OLE2 *ole2, size_t pos) {
++static int ole2_fseek(OLE2 *ole2, size_t pos) {
+     if (ole2->file)
+         return fseek(ole2->file, pos, SEEK_SET);
+ 
+@@ -307,31 +348,31 @@ int ole2_fseek(OLE2 *ole2, size_t pos) {
+     return 0;
+ }
+ 
+-size_t ole2_fread(OLE2 *ole2, void *buffer, size_t size, size_t nitems) {
++static size_t ole2_fread(OLE2 *ole2, void *buffer, size_t buffer_len, size_t size) {
++    if (size > buffer_len)
++        return 0;
++
+     if (ole2->file)
+-        return fread(buffer, size, nitems, ole2->file);
++        return fread(buffer, size, 1, ole2->file);
+ 
+-    size_t i = 0;
+-    for (i=0; i<nitems; i++) {
+-        if (ole2->buffer_pos + size > ole2->buffer_len)
+-            break;
++    if (ole2->buffer_pos + size > ole2->buffer_len)
++        return 0;
+ 
+-        memcpy(buffer, (const char *)ole2->buffer + ole2->buffer_pos, size);
+-        ole2->buffer_pos += size;
+-    }
+-    return i;
+-}
++    memcpy(buffer, (const char *)ole2->buffer + ole2->buffer_pos, size);
++    ole2->buffer_pos += size;
+ 
++    return 1;
++}
+ 
+ // read header and check magic numbers
+ static ssize_t ole2_read_header(OLE2 *ole) {
+     ssize_t bytes_read = 0, total_bytes_read = 0;
+-    OLE2Header *oleh = malloc(512);
+-    if (ole2_fread(ole, oleh, 512, 1) != 1) {
++    OLE2Header *oleh = malloc(sizeof(OLE2Header));
++    if (ole2_fread(ole, oleh, sizeof(OLE2Header), sizeof(OLE2Header)) != 1) {
+         total_bytes_read = -1;
+         goto cleanup;
+     }
+-    total_bytes_read += 512;
++    total_bytes_read += sizeof(OLE2Header);
+     xlsConvertHeader(oleh);
+ 
+ 	// make sure the file looks good. Note: this code only works on Little Endian machines
+@@ -395,11 +436,16 @@ cleanup:
+ 
+ static ssize_t ole2_read_body(OLE2 *ole) {
+ 	// reuse this buffer
+-    PSS *pss = malloc(512);
+-    OLE2Stream *olest=ole2_sopen(ole,ole->dirstart, -1);
++    PSS *pss = NULL;
++    OLE2Stream *olest = NULL;
+     char* name = NULL;
+     ssize_t bytes_read = 0, total_bytes_read = 0;
+ 
++    if ((olest = ole2_sopen(ole,ole->dirstart, -1)) == NULL) {
++        total_bytes_read = -1;
++        goto cleanup;
++    }
++    pss = malloc(sizeof(PSS));
+     do {
+         if ((bytes_read = ole2_read(pss,1,sizeof(PSS),olest)) == -1) {
+             total_bytes_read = -1;
+@@ -449,9 +495,10 @@ static ssize_t ole2_read_body(OLE2 *ole)
+ 			} else if(pss->type == PS_USER_ROOT) {
+ 				DWORD sector, k, blocks;
+ 				BYTE *wptr;
++                size_t bytes_left;
+ 				
+ 				blocks = (pss->size + (ole->lsector - 1)) / ole->lsector;	// count partial
+-				if ((ole->SSAT = ole_malloc(blocks*ole->lsector)) == NULL) {
++				if ((ole->SSAT = ole_realloc(ole->SSAT, blocks*ole->lsector)) == NULL) {
+                     total_bytes_read = -1;
+                     goto cleanup;
+                 }
+@@ -460,45 +507,57 @@ static ssize_t ole2_read_body(OLE2 *ole)
+ 
+ 				sector = pss->sstart;
+ 				wptr = (BYTE*)ole->SSAT;
++                bytes_left = blocks*ole->lsector;
+ 				for(k=0; k<blocks; ++k) {
+ 					// printf("block %d sector %d\n", k, sector);
+-                    if (sector == ENDOFCHAIN || sector_read(ole, wptr, sector) == -1) {
++                    if (sector == ENDOFCHAIN || sector_read(ole, wptr, bytes_left, sector) == -1) {
+                         if (xls_debug) fprintf(stderr, "Unable to read sector #%d\n", sector);
+                         total_bytes_read = -1;
+                         goto cleanup;
+                     }
++                    if (!ole2_validate_sector(sector, ole)) {
++                        total_bytes_read = -1;
++                        goto cleanup;
++                    }
+                     total_bytes_read += ole->lsector;
+ 					wptr += ole->lsector;
++                    bytes_left -= ole->lsector;
+ 					sector = xlsIntVal(ole->SecID[sector]);
+ 				}
+ 			}	
+ 		} else {
+ 			free(name);
+ 		}
+-    }
+-    while (!olest->eof);
++    } while (!olest->eof);
+ 
+ cleanup:
+-	ole2_fclose(olest);
+-    free(pss);
++    if (olest)
++        ole2_fclose(olest);
++    if (pss)
++        free(pss);
+ 
+     return total_bytes_read;
+ }
+ 
+ // Open in-memory buffer
+ OLE2 *ole2_open_buffer(const void *buffer, size_t len) {
+-    OLE2 *ole=(OLE2*)calloc(1, sizeof(OLE2));
++    OLE2 *ole = calloc(1, sizeof(OLE2));
+ 
+     ole->buffer = buffer;
+     ole->buffer_len = len;
+ 
+     if (ole2_read_header(ole) == -1) {
+-        free(ole);
++        ole2_close(ole);
++        return NULL;
++    }
++
++    if (!ole2_validate_chain(ole)) {
++        ole2_close(ole);
+         return NULL;
+     }
+ 
+     if (ole2_read_body(ole) == -1) {
+-        free(ole);
++        ole2_close(ole);
+         return NULL;
+     }
+ 
+@@ -516,7 +575,7 @@ OLE2* ole2_open_file(const char *file)
+ #endif
+ 
+ 	if(xls_debug) printf("ole2_open: %s\n", file);
+-    ole=(OLE2*)calloc(1, sizeof(OLE2));
++    ole = calloc(1, sizeof(OLE2));
+ 
+     if (!(ole->file=fopen(file, "rb"))) {
+         if(xls_debug) fprintf(stderr, "File not found\n");
+@@ -525,14 +584,12 @@ OLE2* ole2_open_file(const char *file)
+     }
+ 
+     if (ole2_read_header(ole) == -1) {
+-		fclose(ole->file);
+-        free(ole);
++        ole2_close(ole);
+         return NULL;
+     }
+ 
+     if (ole2_read_body(ole) == -1) {
+-		fclose(ole->file);
+-        free(ole);
++        ole2_close(ole);
+         return NULL;
+     }
+ 
+@@ -545,14 +602,14 @@ void ole2_close(OLE2* ole2)
+     if (ole2->file)
+         fclose(ole2->file);
+ 
+-	for(i=0; i<ole2->files.count; ++i) {
+-		free(ole2->files.file[i].name);
+-	}
+-	free(ole2->files.file);
+-	free(ole2->SecID);
+-	free(ole2->SSecID);
+-	free(ole2->SSAT);
+-	free(ole2);
++    for(i=0; i<ole2->files.count; ++i) {
++        free(ole2->files.file[i].name);
++    }
++    free(ole2->files.file);
++    free(ole2->SecID);
++    free(ole2->SSecID);
++    free(ole2->SSAT);
++    free(ole2);
+ }
+ 
+ void ole2_fclose(OLE2Stream* ole2st)
+@@ -562,26 +619,25 @@ void ole2_fclose(OLE2Stream* ole2st)
+ }
+ 
+ // Return offset in bytes of a sector from its sid
+-static size_t sector_pos(OLE2* ole2, size_t sid)
++static size_t sector_pos(OLE2* ole2, DWORD sid)
+ {
+     return 512 + sid * ole2->lsector;
+ }
+ // Read one sector from its sid
+-static ssize_t sector_read(OLE2* ole2, void *buffer, size_t sid)
++static ssize_t sector_read(OLE2* ole2, void *buffer, size_t buffer_len, DWORD sid)
+ {
+ 	size_t num;
+ 	size_t seeked;
+ 
+-	//printf("sector_read: sid=%zu (0x%zx) lsector=%u sector_pos=%zu\n", sid, sid, ole2->lsector, sector_pos(ole2, sid) );
+-    seeked = ole2_fseek(ole2, sector_pos(ole2, sid));
+-	if(seeked != 0) {
+-		if (xls_debug) fprintf(stderr, "Error: wanted to seek to sector %zu (0x%zx) loc=%zu\n", sid, sid, sector_pos(ole2, sid));
++	if ((seeked = ole2_fseek(ole2, sector_pos(ole2, sid))) != 0) {
++		if (xls_debug) fprintf(stderr, "Error: wanted to seek to sector %u (0x%x) loc=%u\n", sid, sid,
++                (unsigned int)sector_pos(ole2, sid));
+         return -1;
+     }
+ 
+-	num = ole2_fread(ole2, buffer, ole2->lsector, 1);
+-    if(num != 1) {
+-        if (xls_debug) fprintf(stderr, "Error: fread wanted 1 got %zu loc=%zu\n", num, sector_pos(ole2, sid));
++    if ((num = ole2_fread(ole2, buffer, buffer_len, ole2->lsector)) != 1) {
++        if (xls_debug) fprintf(stderr, "Error: fread wanted 1 got %lu loc=%u\n", (unsigned long)num,
++                (unsigned int)sector_pos(ole2, sid));
+         return -1;
+     }
+ 
+@@ -589,36 +645,38 @@ static ssize_t sector_read(OLE2* ole2, v
+ }
+ 
+ // read first 109 sectors of MSAT from header
+-static ssize_t read_MSAT_header(OLE2* ole2, OLE2Header* oleh, int sectorCount) {
++static ssize_t read_MSAT_header(OLE2* ole2, OLE2Header* oleh, DWORD sectorCount) {
+     BYTE *sector = (BYTE*)ole2->SecID;
+     ssize_t bytes_read = 0, total_bytes_read = 0;
+-    int sectorNum;
++    size_t bytes_left = ole2->SecIDCount * sizeof(DWORD);
++    DWORD sectorNum;
+ 
+-    for (sectorNum = 0; sectorNum < sectorCount; sectorNum++)
++    for (sectorNum = 0; sectorNum < sectorCount && sectorNum < 109; sectorNum++)
+     {
+-        if ((bytes_read = sector_read(ole2, sector, oleh->MSAT[sectorNum])) == -1) {
++        if ((bytes_read = sector_read(ole2, sector, bytes_left, oleh->MSAT[sectorNum])) == -1) {
+             if (xls_debug) fprintf(stderr, "Error: Unable to read sector #%d\n", oleh->MSAT[sectorNum]);
+             return -1;
+         }
+         sector += ole2->lsector;
++        bytes_left -= ole2->lsector;
+         total_bytes_read += bytes_read;
+     }
+     return total_bytes_read;
+ }
+ 
+ // Add additional sectors of the MSAT
+-static ssize_t read_MSAT_body(OLE2 *ole2, int sectorOffset, int sectorCount) {
++static ssize_t read_MSAT_body(OLE2 *ole2, DWORD sectorOffset, DWORD sectorCount) {
+     DWORD sid = ole2->difstart;
+     ssize_t bytes_read = 0, total_bytes_read = 0;
+-    int sectorNum = sectorOffset;
++    DWORD sectorNum = sectorOffset;
+ 
+-    BYTE *sector = ole_malloc(ole2->lsector);
++    DWORD *sector = ole_malloc(ole2->lsector);
+     //printf("sid=%u (0x%x) sector=%u\n", sid, sid, ole2->lsector);
+     while (sid != ENDOFCHAIN && sid != FREESECT) // FREESECT only here due to an actual file that requires it (old Apple Numbers bug)
+     {
+         int posInSector;
+         // read MSAT sector
+-        if ((bytes_read = sector_read(ole2, sector, sid)) == -1) {
++        if ((bytes_read = sector_read(ole2, sector, ole2->lsector, sid)) == -1) {
+             total_bytes_read = -1;
+             if (xls_debug) fprintf(stderr, "Error: Unable to read sector #%d\n", sid);
+             goto cleanup;
+@@ -628,7 +686,7 @@ static ssize_t read_MSAT_body(OLE2 *ole2
+         // read content
+         for (posInSector = 0; posInSector < (ole2->lsector-4)/4; posInSector++)
+         {
+-            DWORD s = *(DWORD_UA *)(sector + posInSector*4);
++            DWORD s = sector[posInSector];
+             //printf("   s[%d]=%d (0x%x)\n", posInSector, s, s);
+ 
+             if (s != ENDOFCHAIN && s != FREESECT) // see patch in Bug 31. For very large files
+@@ -638,7 +696,8 @@ static ssize_t read_MSAT_body(OLE2 *ole2
+                     total_bytes_read = -1;
+                     goto cleanup;
+                 }
+-                if ((bytes_read = sector_read(ole2, (BYTE*)(ole2->SecID)+sectorNum*ole2->lsector, s)) == -1) {
++                if ((bytes_read = sector_read(ole2, (BYTE*)(ole2->SecID)+sectorNum*ole2->lsector,
++                                (ole2->SecIDCount * sizeof(DWORD) - sectorNum*ole2->lsector), s)) == -1) {
+                     if (xls_debug) fprintf(stderr, "Error: Unable to read sector #%d\n", s);
+                     total_bytes_read = -1;
+                     goto cleanup;
+@@ -647,7 +706,7 @@ static ssize_t read_MSAT_body(OLE2 *ole2
+                 sectorNum++;
+             }
+         }
+-        sid = *(DWORD_UA *)(sector + posInSector*4);
++        sid = sector[posInSector];
+         //printf("   s[%d]=%d (0x%x)\n", posInSector, sid, sid);
+     }
+ #ifdef OLE_DEBUG
+@@ -671,32 +730,40 @@ static ssize_t read_MSAT_trailer(OLE2 *o
+     ssize_t total_bytes_read = 0;
+     DWORD sector, k;
+     BYTE *wptr;
++    size_t bytes_left;
+ 
+-	if(ole2->sfatstart != ENDOFCHAIN) {
+-		if ((ole2->SSecID = ole_malloc(ole2->csfat*(size_t)ole2->lsector)) == NULL) {
+-            return -1;
++    if(ole2->sfatstart == ENDOFCHAIN)
++        return 0;
++
++    if ((ole2->SSecID = ole_malloc(ole2->csfat*(size_t)ole2->lsector)) == NULL) {
++        return -1;
++    }
++    ole2->SSecIDCount = ole2->csfat*(size_t)ole2->lsector/4;
++    sector = ole2->sfatstart;
++    wptr=(BYTE*)ole2->SSecID;
++    bytes_left = ole2->SSecIDCount * sizeof(DWORD);
++    for(k=0; k<ole2->csfat; ++k) {
++        if (sector == ENDOFCHAIN || sector_read(ole2, wptr, bytes_left, sector) == -1) {
++            total_bytes_read = -1;
++            goto cleanup;
+         }
+-        ole2->SSecIDCount = ole2->csfat*(size_t)ole2->lsector/4;
+-		sector = ole2->sfatstart;
+-		wptr=(BYTE*)ole2->SSecID;
+-		for(k=0; k<ole2->csfat; ++k) {
+-			if (sector == ENDOFCHAIN || sector_read(ole2, wptr, sector) == -1) {
+-                total_bytes_read = -1;
+-                goto cleanup;
+-            }
+-			wptr += ole2->lsector;
+-            total_bytes_read += ole2->lsector;
+-			sector = ole2->SecID[sector];
+-		}
++        if (!ole2_validate_sector(sector, ole2)) {
++            total_bytes_read = -1;
++            goto cleanup;
++        }
++        wptr += ole2->lsector;
++        bytes_left -= ole2->lsector;
++        total_bytes_read += ole2->lsector;
++        sector = xlsIntVal(ole2->SecID[sector]);
++    }
+ #ifdef OLE_DEBUG
+-		if(xls_debug) {
+-			int i;
+-			for(i=0; i<ole2->csfat; ++i) {
+-				if(ole2->SSecID[i] != FREESECT) fprintf(stderr, "SSecID[%d]=%d\n", i, ole2->SSecID[i]);
+-			}
+-		}
++    if(xls_debug) {
++        int i;
++        for(i=0; i<ole2->csfat; ++i) {
++            if(ole2->SSecID[i] != FREESECT) fprintf(stderr, "SSecID[%d]=%d\n", i, ole2->SSecID[i]);
++        }
++    }
+ #endif
+-	}
+ 
+ cleanup:
+     return total_bytes_read;
+@@ -707,17 +774,20 @@ cleanup:
+ static ssize_t read_MSAT(OLE2* ole2, OLE2Header* oleh)
+ {
+     // reconstitution of the MSAT
+-    int count = (ole2->cfat < 109) ? ole2->cfat : 109;
+-    if(count <= 0) {
+-        if (xls_debug) fprintf(stderr, "Error: MSAT count out-of-bounds\n");
++    DWORD count = ole2->cfat;
++    if(count == 0 || count > (1 << 24)) {
++        if (xls_debug) fprintf(stderr, "Error: MSAT count %u out-of-bounds\n", count);
+         return -1;
+     }
+ 
+     ssize_t total_bytes_read = 0;
+     ssize_t bytes_read = 0;
+ 
+-    ole2->SecID = ole_malloc(count*ole2->lsector);
+     ole2->SecIDCount = count*ole2->lsector/4;
++    if ((ole2->SecID = ole_malloc(ole2->SecIDCount * sizeof(DWORD))) == NULL) {
++        total_bytes_read = -1;
++        goto cleanup;
++    }
+ 
+     if ((bytes_read = read_MSAT_header(ole2, oleh, count)) == -1) {
+         total_bytes_read = -1;
+--- r-cran-readxl-0.1.1.orig/src/xls.c
++++ r-cran-readxl-0.1.1/src/xls.c
+@@ -1,32 +1,35 @@
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  *
+- * This file is part of libxls -- A multiplatform, C/C++ library
+- * for parsing Excel(TM) files.
++ * Copyright 2004 Komarov Valery
++ * Copyright 2006 Christophe Leitienne
++ * Copyright 2008-2017 David Hoerl
++ * Copyright 2013 Bob Colbert
++ * Copyright 2013-2018 Evan Miller
+  *
+- * Redistribution and use in source and binary forms, with or without modification, are
+- * permitted provided that the following conditions are met:
++ * This file is part of libxls -- A multiplatform, C/C++ library for parsing
++ * Excel(TM) files.
+  *
+- *    1. Redistributions of source code must retain the above copyright notice, this list of
+- *       conditions and the following disclaimer.
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+  *
+- *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+- *       of conditions and the following disclaimer in the documentation and/or other materials
+- *       provided with the distribution.
++ *    1. Redistributions of source code must retain the above copyright notice,
++ *    this list of conditions and the following disclaimer.
+  *
+- * THIS SOFTWARE IS PROVIDED BY David Hoerl ''AS IS'' AND ANY EXPRESS OR IMPLIED
+- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David Hoerl OR
+- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *    2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
+  *
+- * Copyright 2004 Komarov Valery
+- * Copyright 2006 Christophe Leitienne
+- * Copyright 2013 Bob Colbert
+- * Copyright 2008-2013 David Hoerl
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS
++ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  */
+ 
+@@ -34,6 +37,7 @@
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
++#include <stddef.h>
+ #include <errno.h>
+ 
+ #include <memory.h>
+@@ -52,7 +56,7 @@
+ //#define DEBUG_DRAWINGS
+ int xls_debug = 0;
+ 
+-static double NumFromRk(DWORD_UA drk);
++static double NumFromRk(DWORD drk);
+ static xls_formula_handler formula_handler;
+ 
+ extern xls_error_t xls_addSST(xlsWorkBook* pWB, SST* sst, DWORD size);
+@@ -73,7 +77,7 @@ extern xls_error_t xls_formatColumn(xlsW
+ extern xls_error_t xls_parseWorkSheet(xlsWorkSheet* pWS);
+ extern void xls_dumpSummary(char *buf, int isSummary, xlsSummaryInfo *pSI);
+ 
+-#ifdef AIX
++#if defined(_AIX) || defined(__sun)
+ #pragma pack(1)
+ #else
+ #pragma pack(push, 1)
+@@ -90,7 +94,7 @@ typedef struct {
+ 	uint32_t		os;
+ 	uint32_t		format[4];
+ 	uint32_t		count;
+-	sectionList		secList[0];
++	sectionList		secList[1];
+ } header;
+ 
+ typedef struct {
+@@ -101,30 +105,14 @@ typedef struct {
+ typedef struct {
+ 	uint32_t		length;
+ 	uint32_t		numProperties;
+-	propertyList	properties[0];
++	propertyList	properties[1];
+ } sectionHeader;
+ 
+ typedef struct {
+ 	uint32_t		propertyID;
+-	uint32_t		data[0];
++	uint32_t		data[1];
+ } property;
+ 
+-#ifdef DEBUG_DRAWINGS
+-struct drawHeader {
+-	unsigned int rec : 4;
+-	unsigned int instance : 12;
+-	unsigned int type : 16;
+-	unsigned int len : 32;
+-};
+-
+-static char *formData;
+-static char *formFunc;
+-static struct drawHeader drawProc(uint8_t *buf, uint32_t maxLen, uint32_t *off, int level);
+-static void dumpRec(char *comment, struct drawHeader *h, int len, uint8_t *buf);
+-static int finder(uint8_t *buf, uint32_t len, uint16_t pattern);
+-static uint32_t sheetOffset;
+-#endif
+-
+ #pragma pack(pop)
+ 
+ int xls(int debug)
+@@ -143,11 +131,17 @@ xls_error_t xls_addSST(xlsWorkBook* pWB,
+     pWB->sst.lastrt=0;
+     pWB->sst.lastsz=0;
+ 
+-    pWB->sst.count = sst->num;
+-    if ((pWB->sst.string = calloc(pWB->sst.count, sizeof(struct str_sst_string))) == NULL)
++    if (sst->num > (1<<24))
++        return LIBXLS_ERROR_MALLOC;
++
++    if (pWB->sst.string)
++        return LIBXLS_ERROR_PARSE;
++
++    if ((pWB->sst.string = calloc(pWB->sst.count = sst->num,
++                    sizeof(struct str_sst_string))) == NULL)
+         return LIBXLS_ERROR_MALLOC;
+ 
+-    return xls_appendSST(pWB,&sst->strings,size-8);
++    return xls_appendSST(pWB, sst->strings, size - offsetof(SST, strings));
+ }
+ 
+ xls_error_t xls_appendSST(xlsWorkBook* pWB, BYTE* buf, DWORD size)
+@@ -180,7 +174,7 @@ xls_error_t xls_appendSST(xlsWorkBook* p
+             if (ofs + 2 > size) {
+                 return LIBXLS_ERROR_PARSE;
+             }
+-            ln=xlsShortVal(*(WORD_UA *)(buf+ofs));
++            ln = buf[ofs+0] + (buf[ofs+1] << 8);
+             rt = 0;
+             sz = 0;
+ 
+@@ -201,19 +195,19 @@ xls_error_t xls_appendSST(xlsWorkBook* p
+ 
+             // Count of rich text formatting runs
+             if (flag & 0x8) {
+-                if (ofs + sizeof(WORD_UA) > size) {
++                if (ofs + sizeof(WORD) > size) {
+                     return LIBXLS_ERROR_PARSE;
+                 }
+-                rt=xlsShortVal(*(WORD_UA *)(buf+ofs));
++                rt = buf[ofs+0] + (buf[ofs+1] << 8);
+                 ofs+=2;
+             }
+ 
+             // Size of asian phonetic settings block
+             if (flag & 0x4) {
+-                if (ofs + sizeof(DWORD_UA) > size) {
++                if (ofs + sizeof(DWORD) > size) {
+                     return LIBXLS_ERROR_PARSE;
+                 }
+-                sz=xlsIntVal(*(DWORD_UA *)(buf+ofs));
++                sz = buf[ofs+0] + (buf[ofs+1] << 8) + (buf[ofs+2] << 16) + ((DWORD)buf[ofs+3] << 24);
+                 ofs+=4;
+ 
+ 				if (xls_debug) {
+@@ -245,7 +239,7 @@ xls_error_t xls_appendSST(xlsWorkBook* p
+                 ofs+=ln_toread*2;
+ 
+                 if (xls_debug) {
+-	                printf("String16SST: %s(%zd)\n",ret,new_len);
++	                printf("String16SST: %s(%lu)\n", ret, (unsigned long)new_len);
+                 }
+             } else {
+                 ln_toread = min((size-ofs), ln);
+@@ -291,7 +285,9 @@ xls_error_t xls_appendSST(xlsWorkBook* p
+ 			if (xls_debug) {
+ 	            printf("String %4u: %s<end>\n", pWB->sst.lastid-1, pWB->sst.string[pWB->sst.lastid-1].str);
+ 			}
+-        }
++        } else {
++            free(ret);
++	}
+ 
+ 		// Jump list of rich text formatting runs
+         if (ofs < size && rt > 0) {
+@@ -325,7 +321,7 @@ xls_error_t xls_appendSST(xlsWorkBook* p
+     return LIBXLS_OK;
+ }
+ 
+-static double NumFromRk(DWORD_UA drk)
++static double NumFromRk(DWORD drk)
+ {
+ 	double ret;
+ 
+@@ -359,7 +355,7 @@ char * xls_addSheet(xlsWorkBook* pWB, BO
+ 
+ 	// printf("charset=%s uni=%d\n", pWB->charset, unicode);
+ 	// printf("bs name %.*s\n", bs->name[0], bs->name+1);
+-	name = get_string(bs->name, size - sizeof(BOUNDSHEET), 0, pWB->is5ver, pWB->charset);
++	name = get_string(bs->name, size - offsetof(BOUNDSHEET, name), 0, pWB->is5ver, pWB->charset);
+ 	// printf("name=%s\n", name);
+ 
+ 	if(xls_debug) {
+@@ -445,43 +441,95 @@ xls_error_t xls_makeTable(xlsWorkSheet*
+         tmp->lcell=pWS->rows.lastcol;
+ 
+ 		tmp->cells.count = pWS->rows.lastcol+1;
+-        if ((tmp->cells.cell = calloc(tmp->cells.count,sizeof(struct st_cell_data))) == NULL)
++        if ((tmp->cells.cell = calloc(tmp->cells.count, sizeof(struct st_cell_data))) == NULL)
+             return LIBXLS_ERROR_MALLOC;
+ 
+         for (i=0;i<=pWS->rows.lastcol;i++)
+         {
+-            tmp->cells.cell[i].col=i;
+-            tmp->cells.cell[i].row=t;
+-            tmp->cells.cell[i].width=pWS->defcolwidth;
+-            tmp->cells.cell[i].xf=0;
+-            tmp->cells.cell[i].str=NULL;
+-            tmp->cells.cell[i].d=0;
+-            tmp->cells.cell[i].l=0;
+-            tmp->cells.cell[i].isHidden=0;
+-            tmp->cells.cell[i].colspan=0;
+-            tmp->cells.cell[i].rowspan=0;
+-            tmp->cells.cell[i].id=XLS_RECORD_BLANK;
+-            tmp->cells.cell[i].str=NULL;
++            tmp->cells.cell[i].col = i;
++            tmp->cells.cell[i].row = t;
++            tmp->cells.cell[i].width = pWS->defcolwidth;
++            tmp->cells.cell[i].id = XLS_RECORD_BLANK;
+         }
+     }
+     return LIBXLS_OK;
+ }
+ 
++int xls_isCellTooSmall(xlsWorkBook* pWB, BOF* bof, BYTE* buf) {
++    if (bof->size < sizeof(COL))
++        return 1;
++
++    if (bof->id == XLS_RECORD_FORMULA || bof->id == XLS_RECORD_FORMULA_ALT)
++        return (bof->size < sizeof(FORMULA));
++
++    if (bof->id == XLS_RECORD_MULRK)
++        return (bof->size < offsetof(MULRK, rk));
++
++    if (bof->id == XLS_RECORD_MULBLANK)
++        return (bof->size < offsetof(MULBLANK, xf));
++
++    if (bof->id == XLS_RECORD_LABELSST)
++        return (bof->size < offsetof(LABEL, value) + (pWB->is5ver ? 2 : 4));
++
++    if (bof->id == XLS_RECORD_LABEL) {
++        if (bof->size < offsetof(LABEL, value) + 2)
++            return 1;
++
++        size_t label_len = ((LABEL*)buf)->value[0] + (((LABEL*)buf)->value[1] << 8);
++        if (pWB->is5ver) {
++            return (bof->size < offsetof(LABEL, value) + 2 + label_len);
++        }
++
++        if (bof->size < offsetof(LABEL, value) + 3)
++            return 1;
++
++        if ((((LABEL*)buf)->value[2] & 0x01) == 0) {
++            return (bof->size < offsetof(LABEL, value) + 3 + label_len);
++        }
++        return (bof->size < offsetof(LABEL, value) + 3 + 2 * label_len);
++    }
++
++    if (bof->id == XLS_RECORD_RK)
++        return (bof->size < sizeof(RK));
++
++    if (bof->id == XLS_RECORD_NUMBER)
++        return (bof->size < sizeof(BR_NUMBER));
++
++    if (bof->id == XLS_RECORD_BOOLERR)
++        return (bof->size < sizeof(BOOLERR));
++
++    return 0;
++}
++
++void xls_cell_set_str(struct st_cell_data *cell, char *str) {
++    if (cell->str) {
++        free(cell->str);
++    }
++    cell->str = str;
++}
++
+ struct st_cell_data *xls_addCell(xlsWorkSheet* pWS,BOF* bof,BYTE* buf)
+ {
+     struct st_cell_data*	cell;
+     struct st_row_data*		row;
++    WORD                    col;
+     int						i;
+ 
+ 	verbose ("xls_addCell");
+ 
+-    if (bof->size < sizeof(COL))
++    if (xls_isCellTooSmall(pWS->workbook, bof, buf))
+         return NULL;
+ 
+ 	// printf("ROW: %u COL: %u\n", xlsShortVal(((COL*)buf)->row), xlsShortVal(((COL*)buf)->col));
+     row=&pWS->rows.row[xlsShortVal(((COL*)buf)->row)];
+-    //cell=&row->cells.cell[((COL*)buf)->col - row->fcell]; DFH - inconsistent
+-    cell=&row->cells.cell[xlsShortVal(((COL*)buf)->col)];
++
++    col = xlsShortVal(((COL*)buf)->col);
++    if (col >= row->cells.count) {
++        if (xls_debug) fprintf(stderr, "Error: Column index out of bounds\n");
++        return NULL;
++    }
++    cell = &row->cells.cell[col];
++
+     cell->id=bof->id;
+     cell->xf=xlsShortVal(((COL*)buf)->xf);
+ 
+@@ -489,16 +537,15 @@ struct st_cell_data *xls_addCell(xlsWork
+     {
+     case XLS_RECORD_FORMULA:
+     case XLS_RECORD_FORMULA_ALT:
+-        if (bof->size < sizeof(FORMULA))
+-            return NULL;
+-
+ 		xlsConvertFormula((FORMULA *)buf);
+         cell->id=XLS_RECORD_FORMULA;
+         if (((FORMULA*)buf)->res!=0xffff) {
+ 			// if a double, then set double and clear l
+ 			cell->l=0;
+ 			memcpy(&cell->d, &((FORMULA*)buf)->resid, sizeof(double));	// Required for ARM
+-			cell->str=xls_getfcell(pWS->workbook,cell, NULL);
++            cell->id = XLS_RECORD_NUMBER; // hack
++            xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
++            cell->id = bof->id;
+ 		} else {
+ 			double d = ((FORMULA*)buf)->resdata[1];
+ 			cell->l = 0xFFFF;
+@@ -507,38 +554,38 @@ struct st_cell_data *xls_addCell(xlsWork
+ 				break;	// cell is half complete, get the STRING next record
+ 			case 1:		// Boolean
+ 				memcpy(&cell->d, &d, sizeof(double)); // Required for ARM
+-				sprintf((char *)(cell->str = malloc(sizeof("bool"))), "bool");
++                xls_cell_set_str(cell, strdup("bool"));
+ 				break;
+ 			case 2:		// error
+ 				memcpy(&cell->d, &d, sizeof(double)); // Required for ARM
+-				sprintf((char *)(cell->str = malloc(sizeof("error"))), "error");
++                xls_cell_set_str(cell, strdup("error"));
+ 				break;
+ 			case 3:		// empty string
+-				cell->str = calloc(1,1);
++                xls_cell_set_str(cell, strdup(""));
+ 				break;
+ 			}
+ 		}
+ 		if(formula_handler) formula_handler(bof->id, bof->size, buf);
+         break;
+     case XLS_RECORD_MULRK:
+-        if (bof->size < sizeof(MULRK))
+-            return NULL;
+         for (i = 0; i < (bof->size - 6)/6; i++)	// 6 == 2 row + 2 col + 2 trailing index
+         {
+-            cell=&row->cells.cell[xlsShortVal(((MULRK*)buf)->col + i)];
+-			// printf("i=%d col=%d\n", i, xlsShortVal(((MULRK*)buf)->col + i) );
++            WORD index = col + i;
++            if(index >= row->cells.count) {
++                if (xls_debug) fprintf(stderr, "Error: MULTI-RK index out of bounds\n");
++                return NULL;
++            }
++            cell=&row->cells.cell[index];
+             cell->id=XLS_RECORD_RK;
+             cell->xf=xlsShortVal(((MULRK*)buf)->rk[i].xf);
+             cell->d=NumFromRk(xlsIntVal(((MULRK*)buf)->rk[i].value));
+-            cell->str=xls_getfcell(pWS->workbook,cell, NULL);
++            xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
+         }
+         break;
+     case XLS_RECORD_MULBLANK:
+-        if (bof->size < sizeof(MULBLANK))
+-            return NULL;
+         for (i = 0; i < (bof->size - 6)/2; i++)	// 6 == 2 row + 2 col + 2 trailing index
+         {
+-            WORD index = xlsShortVal(((MULBLANK*)buf)->col) + i;
++            WORD index = col + i;
+             if(index >= row->cells.count) {
+                 if (xls_debug) fprintf(stderr, "Error: MULTI-BLANK index out of bounds\n");
+                 return NULL;
+@@ -546,46 +593,38 @@ struct st_cell_data *xls_addCell(xlsWork
+             cell=&row->cells.cell[index];
+             cell->id=XLS_RECORD_BLANK;
+             cell->xf=xlsShortVal(((MULBLANK*)buf)->xf[i]);
+-            cell->str=xls_getfcell(pWS->workbook,cell, NULL);
++            xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
+         }
+         break;
+     case XLS_RECORD_LABELSST:
+     case XLS_RECORD_LABEL:
+-        if (bof->size < sizeof(LABEL))
+-            return NULL;
+-		cell->str=xls_getfcell(pWS->workbook,cell,(WORD_UA *)&((LABEL*)buf)->value);
++        xls_cell_set_str(cell, xls_getfcell(pWS->workbook, cell, ((LABEL*)buf)->value));
+         if (cell->str) {
+             sscanf((char *)cell->str, "%d", &cell->l);
+             sscanf((char *)cell->str, "%lf", &cell->d);
+         }
+ 		break;
+     case XLS_RECORD_RK:
+-        if (bof->size < sizeof(RK))
+-            return NULL;
+         cell->d=NumFromRk(xlsIntVal(((RK*)buf)->value));
+-        cell->str=xls_getfcell(pWS->workbook,cell, NULL);
++        xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
+         break;
+     case XLS_RECORD_BLANK:
+         break;
+     case XLS_RECORD_NUMBER:
+-        if (bof->size < sizeof(BR_NUMBER))
+-            return NULL;
+         xlsConvertDouble((BYTE *)&((BR_NUMBER*)buf)->value);
+ 		memcpy(&cell->d, &((BR_NUMBER*)buf)->value, sizeof(double)); // Required for ARM
+-        cell->str=xls_getfcell(pWS->workbook,cell, NULL);
++        xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
+         break;
+     case XLS_RECORD_BOOLERR:
+-        if (bof->size < sizeof(BOOLERR))
+-            return NULL;
+         cell->d = ((BOOLERR *)buf)->value;
+         if (((BOOLERR *)buf)->iserror) {
+-            sprintf((char *)(cell->str = malloc(sizeof("error"))), "error");
++            xls_cell_set_str(cell, strdup("error"));
+         } else {
+-            sprintf((char *)(cell->str = malloc(sizeof("bool"))), "bool");
++            xls_cell_set_str(cell, strdup("bool"));
+         }
+         break;
+     default:
+-        cell->str=xls_getfcell(pWS->workbook,cell, NULL);
++        xls_cell_set_str(cell, xls_getfcell(pWS->workbook,cell, NULL));
+         break;
+     }
+     if (xls_debug) xls_showCell(cell);
+@@ -605,7 +644,7 @@ char *xls_addFont(xlsWorkBook* pWB, FONT
+ 
+     tmp=&pWB->fonts.font[pWB->fonts.count];
+ 
+-    tmp->name = get_string(font->name, size - sizeof(FONT), 0, pWB->is5ver, pWB->charset);
++    tmp->name = get_string(font->name, size - offsetof(FONT, name), 0, pWB->is5ver, pWB->charset);
+ 
+     tmp->height=font->height;
+     tmp->flag=font->flag;
+@@ -633,7 +672,7 @@ xls_error_t xls_addFormat(xlsWorkBook* p
+ 
+     tmp = &pWB->formats.format[pWB->formats.count];
+     tmp->index = format->index;
+-    tmp->value = get_string(format->value, size - sizeof(FORMAT), (BYTE)!pWB->is5ver, (BYTE)pWB->is5ver, pWB->charset);
++    tmp->value = get_string(format->value, size - offsetof(FORMAT, value), (BYTE)!pWB->is5ver, (BYTE)pWB->is5ver, pWB->charset);
+     if(xls_debug) xls_showFormat(tmp);
+     pWB->formats.count++;
+ 
+@@ -721,11 +760,11 @@ xls_error_t xls_addColinfo(xlsWorkSheet*
+ 
+ xls_error_t xls_mergedCells(xlsWorkSheet* pWS,BOF* bof,BYTE* buf)
+ {
+-    if (bof->size < sizeof(WORD_UA))
++    if (bof->size < sizeof(WORD))
+         return LIBXLS_ERROR_PARSE;
+ 
+-    int count=xlsShortVal(*((WORD_UA *)buf));
+-    DWORD limit = sizeof(WORD_UA)+count*sizeof(struct MERGEDCELLS);
++    int count = buf[0] + (buf[1] << 8);
++    DWORD limit = sizeof(WORD)+count*sizeof(struct MERGEDCELLS);
+     if(limit > (DWORD)bof->size) {
+         verbose("Merged Cells Count out of range");
+         return LIBXLS_ERROR_PARSE;
+@@ -757,10 +796,40 @@ xls_error_t xls_mergedCells(xlsWorkSheet
+     return LIBXLS_OK;
+ }
+ 
++int xls_isRecordTooSmall(xlsWorkBook *pWB, BOF *bof1) {
++    switch (bof1->id) {
++        case XLS_RECORD_BOF:	// BIFF5-8
++            return (bof1->size < 2 * sizeof(WORD));
++        case XLS_RECORD_CODEPAGE:
++            return (bof1->size < sizeof(WORD));
++		case XLS_RECORD_WINDOW1:
++            return (bof1->size < sizeof(WIND1));
++        case XLS_RECORD_SST:
++            return (bof1->size < offsetof(SST, strings));
++        case XLS_RECORD_BOUNDSHEET:
++            return (bof1->size < offsetof(BOUNDSHEET, name));
++        case XLS_RECORD_XF:
++			if(pWB->is5ver) {
++                return (bof1->size < sizeof(XF5));
++            }
++            return (bof1->size < sizeof(XF8));
++        case XLS_RECORD_FONT:
++        case XLS_RECORD_FONT_ALT:
++            return (bof1->size < offsetof(FONT, name));
++        case XLS_RECORD_FORMAT:
++            return (bof1->size < offsetof(FORMAT, value));
++		case XLS_RECORD_1904:
++            return (bof1->size < sizeof(BYTE));
++        default:
++            break;
++    }
++    return 0;
++}
++
+ xls_error_t xls_parseWorkBook(xlsWorkBook* pWB)
+ {
+-    BOF bof1 = { 0 };
+-    BOF bof2 = { 0 };
++    BOF bof1 = { .id = 0, .size = 0 };
++    BOF bof2 = { .id = 0, .size = 0 };
+     BYTE* buf = NULL;
+ 	BYTE once = 0;
+     xls_error_t retval = LIBXLS_OK;
+@@ -769,8 +838,9 @@ xls_error_t xls_parseWorkBook(xlsWorkBoo
+     do {
+ 		if(xls_debug > 10) {
+ 			printf("READ WORKBOOK filePos=%ld\n",  (long)pWB->filepos);
+-			printf("  OLE: start=%d pos=%zd size=%zd fatPos=%zu\n",
+-                    pWB->olestr->start, pWB->olestr->pos, pWB->olestr->size, pWB->olestr->fatpos); 
++			printf("  OLE: start=%d pos=%u size=%u fatPos=%u\n",
++                    pWB->olestr->start, (unsigned int)pWB->olestr->pos,
++                    (unsigned int)pWB->olestr->size, (unsigned int)pWB->olestr->fatpos); 
+ 		}
+ 
+         if (ole2_read(&bof1, 1, 4, pWB->olestr) != 4) {
+@@ -793,37 +863,27 @@ xls_error_t xls_parseWorkBook(xlsWorkBoo
+             }
+         }
+ 
++        if (xls_isRecordTooSmall(pWB, &bof1)) {
++            retval = LIBXLS_ERROR_PARSE;
++            goto cleanup;
++        }
++
+         switch (bof1.id) {
+         case XLS_RECORD_EOF:
+             //verbose("EOF");
+             break;
+         case XLS_RECORD_BOF:	// BIFF5-8
+-            if (bof1.size < sizeof(BIFF)) {
+-                retval = LIBXLS_ERROR_PARSE;
+-                goto cleanup;
+-            }
+-            {
+-				BIFF *b = (BIFF*)buf;
+-                xlsConvertBiff(b);
+-				if (b->ver==0x600)
+-					pWB->is5ver=0;
+-				else
+-					pWB->is5ver=1;
+-				pWB->type=b->type;
++            pWB->is5ver = (buf[0] + (buf[1] << 8) != 0x600);
++            pWB->type = buf[2] + (buf[3] << 8);
+ 
+-				if(xls_debug) {
+-					printf("version: %s\n", pWB->is5ver ? "BIFF5" : "BIFF8" );
+-					printf("   type: %.2X\n", pWB->type);
+-				}
+-			}
++            if(xls_debug) {
++                printf("version: %s\n", pWB->is5ver ? "BIFF5" : "BIFF8" );
++                printf("   type: %.2X\n", pWB->type);
++            }
+             break;
+ 
+         case XLS_RECORD_CODEPAGE:
+-            if (bof1.size < sizeof(WORD_UA)) {
+-                retval = LIBXLS_ERROR_PARSE;
+-                goto cleanup;
+-            }
+-            pWB->codepage=xlsShortVal(*(WORD_UA *)buf);
++            pWB->codepage = buf[0] + (buf[1] << 8);
+ 			if(xls_debug) printf("codepage=%x\n", pWB->codepage);
+             break;
+ 
+@@ -838,10 +898,6 @@ xls_error_t xls_parseWorkBook(xlsWorkBoo
+             break;
+ 
+ 		case XLS_RECORD_WINDOW1:
+-            if (bof1.size < sizeof(WIND1)) {
+-                retval = LIBXLS_ERROR_PARSE;
+-                goto cleanup;
+-            }
+ 			{
+ 				WIND1 *w = (WIND1*)buf;
+                 xlsConvertWindow(w);
+@@ -862,10 +918,6 @@ xls_error_t xls_parseWorkBook(xlsWorkBoo
+ 			break;
+ 
+         case XLS_RECORD_SST:
+-            if (bof1.size < sizeof(SST)) {
+-                retval = LIBXLS_ERROR_PARSE;
+-                goto cleanup;
+-            }
+ 			//printf("ADD SST\n");
+ 			//if(xls_debug) dumpbuf((BYTE *)"/tmp/SST",bof1.size,buf);
+             xlsConvertSst((SST *)buf);
+@@ -879,10 +931,6 @@ xls_error_t xls_parseWorkBook(xlsWorkBoo
+             break;
+ 
+         case XLS_RECORD_BOUNDSHEET:
+-            if (bof1.size < sizeof(BOUNDSHEET)) {
+-                retval = LIBXLS_ERROR_PARSE;
+-                goto cleanup;
+-            }
+ 			{
+ 				//printf("ADD SHEET\n");
+ 				BOUNDSHEET *bs = (BOUNDSHEET *)buf;
+@@ -895,10 +943,6 @@ xls_error_t xls_parseWorkBook(xlsWorkBoo
+ 
+         case XLS_RECORD_XF:
+ 			if(pWB->is5ver) {
+-                if (bof1.size < sizeof(XF5)) {
+-                    retval = LIBXLS_ERROR_PARSE;
+-                    goto cleanup;
+-                }
+ 				XF5 *xf;
+ 				xf = (XF5 *)buf;
+                 xlsConvertXf5(xf);
+@@ -917,10 +961,6 @@ xls_error_t xls_parseWorkBook(xlsWorkBoo
+ 					printf("linesty: %.4x\n", xf->linestyle);
+ 				}
+ 			} else {
+-                if (bof1.size < sizeof(XF8)) {
+-                    retval = LIBXLS_ERROR_PARSE;
+-                    goto cleanup;
+-                }
+ 				XF8 *xf;
+ 				xf = (XF8 *)buf;
+                 xlsConvertXf8(xf);
+@@ -937,10 +977,6 @@ xls_error_t xls_parseWorkBook(xlsWorkBoo
+ 
+         case XLS_RECORD_FONT:
+         case XLS_RECORD_FONT_ALT:
+-            if (bof1.size < sizeof(FONT)) {
+-                retval = LIBXLS_ERROR_PARSE;
+-                goto cleanup;
+-            }
+ 			{
+ 				char *s;
+ 				FONT *f = (FONT*)buf;
+@@ -961,10 +997,6 @@ xls_error_t xls_parseWorkBook(xlsWorkBoo
+ 			break;
+ 
+         case XLS_RECORD_FORMAT:
+-            if (bof1.size < sizeof(FORMAT)) {
+-                retval = LIBXLS_ERROR_PARSE;
+-                goto cleanup;
+-            }
+             xlsConvertFormat((FORMAT *)buf);
+             if ((retval = xls_addFormat(pWB, (FORMAT*)buf, bof1.size)) != LIBXLS_OK) {
+                 goto cleanup;
+@@ -983,6 +1015,7 @@ xls_error_t xls_parseWorkBook(xlsWorkBoo
+ 				} else {
+ 					char *s = get_string((char *)&buf[2], bof1.size - 2, 1, pWB->is5ver, pWB->charset);
+ 					printf("  name=%s\n", s);
++                    free(s);
+ 				}
+ 			}
+ 			break;
+@@ -992,7 +1025,7 @@ xls_error_t xls_parseWorkBook(xlsWorkBoo
+ 				unsigned char *p = buf + 2;
+ 				int idx, len;
+ 
+-				len = *(WORD_UA *)buf;
++				len = buf[0] + (buf[1] << 8);
+ 				for(idx=0; idx<len; ++idx) {
+ 					printf("   Index=0x%2.2x %2.2x%2.2x%2.2x\n", idx+8, p[0], p[1], p[2] );
+ 					p += 4;
+@@ -1001,10 +1034,6 @@ xls_error_t xls_parseWorkBook(xlsWorkBoo
+ 			break;
+ 
+ 		case XLS_RECORD_1904:
+-            if (bof1.size < sizeof(BYTE)) {
+-                retval = LIBXLS_ERROR_PARSE;
+-                goto cleanup;
+-            }
+ 			pWB->is1904 = *(BYTE *)buf;	// the field is a short, but with little endian the first byte is 0 or 1
+ 			if(xls_debug) {
+ 				printf("   mode: 0x%x\n", pWB->is1904);
+@@ -1020,26 +1049,6 @@ xls_error_t xls_parseWorkBook(xlsWorkBoo
+ 			}
+ 			break;
+ 			
+-#ifdef DEBUG_DRAWINGS
+-		case XLS_RECORD_MSODRAWINGGROUP:
+-		{
+-			printf("DRAWING GROUP size=%d\n", bof1.size);
+-			unsigned int total = bof1.size;
+-			unsigned int off = 0;
+-
+-			while(off < total) {
+-				struct drawHeader fooper = drawProc(buf, total, &off, 0);
+-				(void)fooper;
+-			}
+-			printf("Total=%d off=%d\n", total, off);
+-			
+-			if(formData) printf("%s\n", formData);
+-			if(formFunc) printf("%s\n", formFunc);
+-			free(formData), formData = NULL;
+-			free(formFunc), formFunc = NULL;
+-
+-		}	break;
+-#endif
+         default:
+ 			if(xls_debug)
+ 			{
+@@ -1098,11 +1107,11 @@ xls_error_t xls_preparseWorkSheet(xlsWor
+         switch (tmp.id)
+         {
+         case XLS_RECORD_DEFCOLWIDTH:
+-            if (tmp.size < sizeof(WORD_UA)) {
++            if (tmp.size < sizeof(WORD)) {
+                 retval = LIBXLS_ERROR_PARSE;
+                 goto cleanup;
+             }
+-            pWS->defcolwidth=xlsShortVal(*(WORD_UA *)buf)*256;
++            pWS->defcolwidth = (buf[0] << 8) + (buf[1] << 16);
+             break;
+         case XLS_RECORD_COLINFO:
+             if (tmp.size < sizeof(COLINFO)) {
+@@ -1127,7 +1136,7 @@ xls_error_t xls_preparseWorkSheet(xlsWor
+         /* If the ROW record is incorrect or missing, infer the information from
+          * cell data. */
+         case XLS_RECORD_MULRK:
+-            if (tmp.size < sizeof(MULRK)) {
++            if (xls_isCellTooSmall(pWS->workbook, &tmp, buf)) {
+                 retval = LIBXLS_ERROR_PARSE;
+                 goto cleanup;
+             }
+@@ -1137,7 +1146,7 @@ xls_error_t xls_preparseWorkSheet(xlsWor
+                 pWS->rows.lastrow=xlsShortVal(((MULRK*)buf)->row);
+             break;
+         case XLS_RECORD_MULBLANK:
+-            if (tmp.size < sizeof(MULBLANK)) {
++            if (xls_isCellTooSmall(pWS->workbook, &tmp, buf)) {
+                 retval = LIBXLS_ERROR_PARSE;
+                 goto cleanup;
+             }
+@@ -1154,7 +1163,7 @@ xls_error_t xls_preparseWorkSheet(xlsWor
+         case XLS_RECORD_FORMULA:
+         case XLS_RECORD_FORMULA_ALT:
+         case XLS_RECORD_BOOLERR:
+-            if (tmp.size < sizeof(COL)) {
++            if (xls_isCellTooSmall(pWS->workbook, &tmp, buf)) {
+                 retval = LIBXLS_ERROR_PARSE;
+                 goto cleanup;
+             }
+@@ -1164,6 +1173,10 @@ xls_error_t xls_preparseWorkSheet(xlsWor
+                 pWS->rows.lastrow=xlsShortVal(((COL*)buf)->row);
+             break;
+         }
++        if (pWS->rows.lastcol > 256) {
++            retval = LIBXLS_ERROR_PARSE;
++            goto cleanup;
++        }
+     }
+     while ((!pWS->workbook->olestr->eof)&&(tmp.id!=XLS_RECORD_EOF));
+ 
+@@ -1209,9 +1222,6 @@ xls_error_t xls_parseWorkSheet(xlsWorkSh
+ 	long offset = pWS->filepos;
+     size_t read;
+     xls_error_t retval = 0;
+-#ifdef DEBUG_DRAWINGS
+-	int continueRec = 0;
+-#endif
+ 
+ 	struct st_cell_data *cell = NULL;
+ 	xlsWorkBook *pWB = pWS->workbook;
+@@ -1240,7 +1250,7 @@ xls_error_t xls_parseWorkSheet(xlsWorkSh
+ 		long lastPos = offset;
+ 
+ 		if(xls_debug > 10) {
+-			printf("LASTPOS=%ld pos=%zd filePos=%d filePos=%d\n", lastPos, pWB->olestr->pos, pWS->filepos, pWB->filepos);
++			printf("LASTPOS=%ld pos=%d filePos=%d filePos=%d\n", lastPos, (int)pWB->olestr->pos, pWS->filepos, pWB->filepos);
+ 		}
+ 		if((read = ole2_read(&tmp, 1, 4, pWS->workbook->olestr)) != 4) {
+             if (xls_debug) fprintf(stderr, "Error: failed to read OLE size\n");
+@@ -1286,22 +1296,22 @@ xls_error_t xls_parseWorkSheet(xlsWorkSh
+             }
+             break;
+ 		case XLS_RECORD_DEFCOLWIDTH:
+-            if (tmp.size < sizeof(WORD_UA)) {
++            if (tmp.size < sizeof(WORD)) {
+                 retval = LIBXLS_ERROR_PARSE;
+                 goto cleanup;
+             }
+-			if(xls_debug > 10) printf("DEFAULT COL WIDTH: %d\n", *(WORD_UA *)buf);
++			if(xls_debug > 10) printf("DEFAULT COL WIDTH: %d\n", ((WORD *)buf)[0]);
+ 			break;
+ 		case XLS_RECORD_DEFAULTROWHEIGHT:
+-            if (tmp.size < 2 * sizeof(WORD_UA)) {
++            if (tmp.size < 2 * sizeof(WORD)) {
+                 retval = LIBXLS_ERROR_PARSE;
+                 goto cleanup;
+             }
+-			if(xls_debug > 10) printf("DEFAULT ROW Height: 0x%x %d\n", ((WORD_UA *)buf)[0], ((WORD_UA *)buf)[1]);
++			if(xls_debug > 10) printf("DEFAULT ROW Height: 0x%x %d\n", ((WORD *)buf)[0], ((WORD *)buf)[1]);
+ 			break;
+ 		case XLS_RECORD_DBCELL:
+ 			if(xls_debug > 10) {
+-				DWORD *foo = (DWORD_UA *)buf;
++				DWORD *foo = (DWORD *)buf;
+                 WORD *goo;
+ 				int i;
+                 printf("DBCELL: size %d\n", tmp.size);
+@@ -1313,7 +1323,7 @@ xls_error_t xls_parseWorkSheet(xlsWorkSh
+ 			break;
+         case XLS_RECORD_INDEX:
+ 			if(xls_debug > 10) {
+-				DWORD *foo = (DWORD_UA *)buf;
++				DWORD *foo = (DWORD *)buf;
+                 int i;
+ 				printf("INDEX: size %d\n", tmp.size);
+ 				for(i=0; i<5; ++i) printf("FOO[%d]=%4.4x %u\n", i, foo[i], foo[i]);
+@@ -1347,204 +1357,13 @@ xls_error_t xls_parseWorkSheet(xlsWorkSh
+ 
+ 		case XLS_RECORD_STRING:
+ 			if(cell && (cell->id == XLS_RECORD_FORMULA || cell->id == XLS_RECORD_FORMULA_ALT)) {
+-				cell->str = get_string((char *)buf, tmp.size, (BYTE)!pWB->is5ver, pWB->is5ver, pWB->charset);
++                xls_cell_set_str(cell, get_string((char *)buf, tmp.size,
++                            (BYTE)!pWB->is5ver, pWB->is5ver, pWB->charset));
+ 				if (xls_debug) xls_showCell(cell);
+ 			}
+ 			break;
+-#if 0 // debugging
+-		case XLS_RECORD_HYPERREF:
+-			if(xls_debug) {
+-				printf("HYPERREF: ");
+-				unsigned char xx, *foo = (void *)buf;
+-
+-				for(xx=0; xx<tmp.size; ++xx, ++foo) {
+-					printf("%2.2x ", *foo);
+-				}
+-				printf("\n");
+-			}
+-			break;
+-		case XLS_RECORD_WINDOW2:
+-			if(xls_debug) {
+-				printf("WINDOW2: ");
+-				unsigned short xx, *foo = (void *)buf;
+-
+-				for(xx=0; xx<7; ++xx, ++foo) {
+-					printf("0x%4.4x ", *foo);
+-				}
+-				printf("\n");
+-			}
+-			break;
+-#endif
+-
+-#ifdef DEBUG_DRAWINGS
+-#ifdef AIX
+-#pragma pack(1)
+-#else
+-#pragma pack(push, 1)
+-#endif
+-		case XLS_RECORD_MSODRAWING:	// MSDRAWING
+-		{
+-			printf("DRAWING size=%d\n", tmp.size);
+-			sheetOffset = 100;
+-			unsigned int total = tmp.size;
+-			unsigned int off = 0;
+-			
+-			while(off < total) {
+-				struct drawHeader fooper  = drawProc(buf, total, &off, 0);
+-				(void)fooper;
+-				printf("---------------Total=%d off=%d\n", total, off);
+-			}
+-
+-			if(formData) printf("%s\n", formData);
+-			if(formFunc) printf("%s\n", formFunc);
+-			free(formData), formData = NULL;
+-			free(formFunc), formFunc = NULL;
+-			
+-		}	break;
+-		
+-		case XLS_RECORD_TXO:
+-		{
+-			struct {
+-				uint16_t	grbit;
+-				uint16_t	rot;
+-				char		reserved1[6];
+-				uint16_t	cchText;
+-				uint16_t	cbRuns;
+-				uint16_t	ifntEmpty;
+-				uint16_t	reserved2;
+-			} foo;
+-			memcpy(&foo, buf, 18);
+-			printf("TXO: grbit=0x%4.4X rot=0x%4.4X chText=0x%4.4X cbRuns=0x%4.4X ifntEmpty=0x%X reserved2=0x%X\n",
+-                    foo.grbit, foo.rot, foo.cchText, foo.cbRuns, foo.ifntEmpty, foo.reserved2);
+-			
+-			printf("Res1: ");
+-			for(int i=0; i<6; ++i) printf("%2.2x ", foo.reserved1[i]);
+-			printf("\n");
+-			
+-			continueRec = 1;
+-			goto printBOF;
+-		}	break;
+-		
+-		case XLS_RECORD_CONTINUE:
+-		{
+-			if(continueRec == 1) {
+-				continueRec = 2;
+-				
+-				printf("TEXT: ");
+-				for(int i=0; i<tmp.size; ++i) printf("%2.2x ", buf[i]);
+-				printf("\n");
+-				printf("\"%.*s\"\n", tmp.size-1, buf+1);
+-			} else
+-			if(continueRec == 2) {
+-				continueRec = 0;
+-				int off = 0;
+-
+-				struct {
+-					uint16_t	ichFirst;
+-					uint16_t	ifnt;
+-					char		reserved[4];
+-				} foo;
+-				
+-				for(int i=0; i<tmp.size/8; ++i) {
+-					memcpy(&foo, buf+off, 8);
+-					printf("TXORUN: %d 0x%x\n", foo.ichFirst, foo.ifnt);
+-					off += 8;
+-				}
+-			}
+-			goto printBOF;
+-		} break;
+-		
+-		case XLS_RECORD_OBJ:
+-			xls_showBOF(&tmp);
+-		{
+-			struct  {
+-				uint16_t	ft;
+-				uint16_t	cb;
+-				uint16_t	ot;
+-				uint16_t	idx;
+-				uint16_t	flags;
+-				uint16_t	unused[6];
+-			} foo;
+-			memcpy(&foo, buf, sizeof(foo));
+-			
+-			int len = (int)(tmp.size - sizeof(foo));
+-			int off = sizeof(foo);
+-			
+-			printf("OBJ ft=0x%X cb=0x%X ot=0x%X idx=0x%X flags=0x%X len=%d ",
+-                    foo.ft, foo.cb, foo.ot, foo.idx, foo.flags, (int)(tmp.size - sizeof(foo)) );
+-			//for(int i=0; i<6; ++i) printf(" 0x%02.2x", foo.unused[i]);
+-			printf("\n");
+-			
+-			if(foo.ot == 0x08) {
+-				struct {
+-					uint16_t ft;
+-					uint16_t cb;
+-					uint16_t flags;
+-				} ftcf;
+-				memcpy(&ftcf, buf+off, sizeof(ftcf));
+-				printf(" ft=%x cb=%x flags=%4.4x\n", ftcf.ft, ftcf.cb, ftcf.flags);
+-				off += sizeof(ftcf);
+-
+-				struct {
+-					uint16_t ft;
+-					uint16_t cb;
+-					uint16_t flags;
+-				} FtPioGrbit;
+-				memcpy(&FtPioGrbit, buf+off, sizeof(FtPioGrbit));
+-				printf(" ft=%x cb=%x flags=%4.4x\n", FtPioGrbit.ft, FtPioGrbit.cb, FtPioGrbit.flags);
+-				off += sizeof(FtPioGrbit);
+-			} else {
+-				printf("Extra: ");
+-				for(int i=0; i<len; ++i) printf("%2.2x ", buf[i+off]);
+-				printf("\n");
+-			}
+-
+-#if 0
+-			struct {
+-				uint16_t	ft;
+-				uint16_t	cb;
+-				uint8_t		guid[16];
+-				uint16_t	fSharedNote;
+-				uint32_t	unused;
+-			} FtNts;
+-			memcpy(&FtNts, buf+off, sizeof(FtNts));
+-			off += sizeof(FtNts);
+-			printf("  ft=%X cb=%X fSharedNote=0x%X guid: ", FtNts.ft, FtNts.cb, FtNts.fSharedNote);
+-			for(int i=0; i<16; ++i) printf("%2.2x ", FtNts.guid[i]);
+-			printf("\n");
+-			
+-			uint32_t last;
+-			memcpy(&last, buf+off, 4);
+-			printf("  LAST 0x%8.8X off=%d s1=%ld s2=%ld\n", last, off+4, sizeof(foo), sizeof(FtNts) );
+-#endif
+-			goto printBOF;
+-		}	break;
+-		
+-		case XLS_RECORD_NOTE:
+-		{
+-			struct {
+-				uint16_t	row;
+-				uint16_t	col;
+-				uint16_t	flags;
+-				uint16_t	idx;
+-				uint16_t	strLen;
+-				uint8_t		strType;
+-			} note;
+-			memcpy(&note, buf, sizeof(note));
+-			printf("   NOTE: row=%d col=%d flags=0x%x idx=%d strLen=%d strType=%d :  ",
+-                    note.row, note.col, note.flags, note.idx, note.strLen, note.strType);
+-			for(int i=0; i<note.strLen; ++i) printf("%2.2x ", buf[i+sizeof(note)]);
+-			printf("\n  %.*s now at %ld len=%d\n", note.strLen, buf + sizeof(note), sizeof(note)+note.strLen, tmp.size);
+-
+-			goto printBOF;
+-		}	break;
+-#pragma pack(pop)
+-#endif
+ 
+         default:
+-#ifdef DEBUG_DRAWINGS
+-		  printBOF:
+-#endif
+ 			if(xls_debug)
+ 			{
+ 				//xls_showBOF(&tmp);
+@@ -1571,7 +1390,7 @@ xlsWorkSheet * xls_getWorkSheet(xlsWorkB
+ {
+     xlsWorkSheet * pWS = NULL;
+     verbose ("xls_getWorkSheet");
+-    if (num >= 0 && num < pWB->sheets.count) {
++    if (num >= 0 && num < (int)pWB->sheets.count) {
+         pWS = calloc(1, sizeof(xlsWorkSheet));
+         pWS->filepos=pWB->sheets.sheet[num].filepos;
+         pWS->workbook=pWB;
+@@ -1694,21 +1513,24 @@ xlsWorkBook *xls_open_buffer(const unsig
+ 
+ xlsRow *xls_row(xlsWorkSheet* pWS, WORD cellRow)
+ {
+-    struct st_row_data *row;
++    if(cellRow > pWS->rows.lastrow)
++        return NULL;
+ 
+-    if(cellRow > pWS->rows.lastrow) return NULL;
+-    row = &pWS->rows.row[cellRow];
++    if (pWS->rows.row == NULL)
++        return NULL;
+ 
+-    return row;
++    return &pWS->rows.row[cellRow];
+ }
+ 
+ xlsCell	*xls_cell(xlsWorkSheet* pWS, WORD cellRow, WORD cellCol)
+ {
+     struct st_row_data	*row;
+ 
+-    if(cellRow > pWS->rows.lastrow) return NULL;
+-    row = &pWS->rows.row[cellRow];
+-    if(cellCol >= row->lcell) return NULL;
++    if ((row = xls_row(pWS, cellRow)) == NULL)
++        return NULL;
++
++    if(cellCol >= row->cells.count)
++        return NULL;
+ 
+     return &row->cells.cell[cellCol];
+ }
+@@ -1784,8 +1606,7 @@ void xls_close_WS(xlsWorkSheet* pWS)
+ {
+ 	if(!pWS) return;
+ 
+-    // ROWS
+-    {
++    if (pWS->rows.row) {
+         DWORD i, j;
+         for(j=0; j<=pWS->rows.lastrow; ++j) {
+             struct st_row_data *row = &pWS->rows.row[j];
+@@ -1795,7 +1616,6 @@ void xls_close_WS(xlsWorkSheet* pWS)
+             free(row->cells.cell);
+         }
+         free(pWS->rows.row);
+-
+     }
+ 
+     // COLINFO
+@@ -1955,498 +1775,3 @@ void xls_set_formula_hander(xls_formula_
+ {
+ 	formula_handler = handler;
+ }
+-
+-#ifdef DEBUG_DRAWINGS
+-
+-#ifdef AIX
+-#pragma pack(1)
+-#else
+-#pragma pack(push, 1)
+-#endif
+-
+-static char spaces[] = "                                                                                                                ";
+-
+-static struct drawHeader drawProc(uint8_t *buf, uint32_t maxLen, uint32_t *off_p, int level)
+-{
+-	struct drawHeader head = { 0, 0, 0, 0 };
+-	uint32_t off = off_p ? *off_p : 0;
+-	memcpy(&head, buf+off, sizeof(head));
+-#if 0	// rec is the lower 4 bits
+-	{
+-		uint16_t foo0, foo1;
+-		uint32_t foo2;
+-		memcpy(&foo0, buf+off, 2);
+-		memcpy(&foo1, buf+off+2, 2);
+-		memcpy(&foo2, buf+off+4, 4);
+-		printf("-----------------------------[%4.4x %4.4x %x] rec=%x instance=%x type=%x len=%x\n", foo0, foo1, foo2, head.rec, head.instance,  head.type, head.len);
+-	}
+-#endif
+-	off += sizeof(head);
+-
+-	printf("%.*s", level*3, spaces);
+-	printf("type=%x rec=%x instance=%x len=%d    ", head.type, head.rec, head.instance, head.len);
+-	
+-	switch(head.type) {
+-	case 0xF000:	// OfficeArtDggContainer - F000 - overall header
+-	{
+-		printf("OfficeArtDggContainer\n");
+-		dumpRec("OfficeArtDggContainer", &head, 0, NULL);
+-
+-		int startOff = off;
+-		while( (off - startOff) < head.len && off < maxLen) {
+-			struct drawHeader fooper2 = drawProc(buf, maxLen, &off, level+1);
+-			(void)fooper2;
+-		}
+-		
+-		printf("%.*s", level*3, spaces);
+-		printf("Total=%d off=%d ObjectSize=%d\n", maxLen, off, off-startOff);
+-		
+-	}	break;
+-
+-#if 0
+-	DRAWING 0xf002 208
+-	  rec=0 instance=1 type=f008 len=8
+-	  csp=4 spidCur=1027
+-	rec=f instance=0 type=f003 len=462
+-	Total=208 off=486
+-	OBJ id=1 ot=0x19 flags=0x4011 check=0x0 len=30
+-	  ft=D cb=16 fSharedNote=0x0 guid: 8e 2e 69 ed f2 7d e3 11 99 7f 00 16 cb 93 e7 b5 
+-	  LAST 0x00000000
+-	type=f00d rec=0 instance=0 len=0    WTF ?!?!?!
+-
+-#endif
+-	case 0xF002:
+-	{
+-		printf("OfficeArtDgContainer\n");
+-		dumpRec("OfficeArtDgContainer", &head, 0, NULL);
+-
+-		int startOff = off;
+-		while( (off - startOff) < head.len && off < maxLen) {
+-			struct drawHeader fooper2 = drawProc(buf, maxLen, &off, level+1);
+-			(void)fooper2;
+-		}
+-		
+-		printf("%.*s", level*3, spaces);
+-		printf("Total=%d off=%d ObjectSize=%d\n", maxLen, off, off-startOff);
+-
+-	}	break;
+-
+-	case 0xF003:
+-	{
+-		printf("OfficeArtSpgrContainer\n");
+-		dumpRec("OfficeArtSpgrContainer", &head, 0, NULL);
+-
+-		int startOff = off;
+-		while( (off - startOff) < head.len && off < maxLen) {
+-			struct drawHeader fooper2 = drawProc(buf, maxLen, &off, level+1);
+-			(void)fooper2;
+-		}
+-		
+-		printf("%.*s", level*3, spaces);
+-		printf("Total=%d off=%d ObjectSize=%d  FIXME FIXME FIXME\n", maxLen, off, off-startOff);
+-	}	break;
+-
+-	case 0xF001:
+-	{
+-		printf("OfficeArtBStoreContainer\n");
+-		dumpRec("OfficeArtBStoreContainer", &head, 0, NULL);
+-
+-		int startOff = off;
+-		while( (off - startOff) < head.len && off < maxLen) {
+-			struct drawHeader fooper2 = drawProc(buf, maxLen, &off, level+1);
+-			(void)fooper2;
+-		}
+-		
+-		printf("%.*s", level*3, spaces);
+-		printf("Total=%d off=%d ObjectSize=%d\n", maxLen, off, off-startOff);
+-		}	break;
+-	case 0xF004:
+-	{
+-		printf("OfficeArtSpContainer\n");
+-		dumpRec("OfficeArtSpContainer", &head, 0, NULL);
+-
+-		int startOff = off;
+-		while( (off - startOff) < head.len && off < maxLen) {
+-			struct drawHeader fooper2 = drawProc(buf, maxLen, &off, level+1);
+-			(void)fooper2;
+-		}
+-		
+-		printf("%.*s", level*3, spaces);
+-		printf("Total=%d off=%d ObjectSize=%d\n", maxLen, off, off-startOff);
+-		}	break;
+-	case 0xF006:
+-	{
+-		// A value that MUST be 0x00000010 + ((head.cidcl - 1) * 0x00000008)
+-		unsigned int count =  (head.len - 0x10) / 0x8;
+-		printf("OfficeArtFDGGBlock count=%d\n", count);
+-		dumpRec("OfficeArtFDGGBlock - needs to be set", &head, 0, NULL);
+-
+-		// OfficeArtFDGG
+-		struct {
+-			uint32_t spidMax;
+-			uint32_t cidcl;
+-			uint32_t cspSaved;
+-			uint32_t cdgSaved;
+-		} fog;
+-		memcpy(&fog, buf+off, 16); // OfficeArtRecordHeader F001 - specified BLIP - this is the image
+-		off += 16;
+-		printf("%.*s", level*3, spaces);
+-		printf(" spidMax=%d cidcl=%d cspSaved=%d cdgSaved=%d\n", fog.spidMax, fog.cidcl, fog.cspSaved, fog.cdgSaved);
+-#if 0
+-		spidMax (4 bytes): An MSOSPID structure, as defined in section 2.1.2, specifying the current maximum shape identifier that is used in any drawing. This value MUST be less than 0x03FFD7FF.
+-		cidcl (4 bytes): An unsigned integer that specifies the number of OfficeArtIDCL records, as defined in section 2.2.46, + 1. This value MUST be less than 0x0FFFFFFF.
+-		cspSaved (4 bytes): An unsigned integer specifying the total number of shapes that have been saved in all of the drawings.
+-		cdgSaved (4 bytes): An unsigned integer specifying the total number of drawings that have been saved in the file.
+-#endif
+-		// OfficeArtIDCL - clusters
+-		for(int i=0; i<count; ++i) {
+-			struct {
+-				uint32_t dgid;
+-				uint32_t cspidCur;
+-#if 0
+-				dgid (4 bytes): An MSODGID structure, as defined in section 2.1.1, specifying the drawing identifier that owns this identifier cluster.
+-				cspidCur (4 bytes): An unsigned integer that, if less than 0x00000400, specifies the largest shape identifier that is currently assigned in this cluster, or that otherwise specifies that no shapes can be added to the drawing.
+-#endif
+-			} foo1;
+-			memcpy(&foo1, buf+off, 8); // OfficeArtIDCL
+-			off += 8;
+-			
+-			printf("%.*s", level*3, spaces);
+-			printf("  dgid=%d cspid=%d\n", foo1.dgid, foo1.cspidCur);
+-		}
+-		//for(int i=0; i<16; ++i) printf(" %2.2x", *(BYTE *)(buf+off+i));
+-		//printf("\n");
+-	}	break;
+-
+-	case 0xF007:
+-	{
+-		printf("OfficeArtFBSE\n");
+-		//dumpRec("OfficeArtFBSE", &head, 0, NULL);
+-		struct {
+-			uint8_t		btWin32;
+-			uint8_t		btMacOS;
+-			uint8_t		rgbUid[16];
+-			uint16_t	tag;
+-			uint32_t	size;
+-			uint32_t	cRef;
+-			uint32_t	foDelay;
+-			uint8_t		unused1;
+-			uint8_t		cbName;
+-			uint8_t		unused2;
+-			uint8_t		unused3;
+-		} fooper1;
+-		memcpy(&fooper1, buf+off, sizeof(fooper1));
+-		off += sizeof(fooper1);
+-		printf("%.*s", level*3, spaces);
+-		printf(" rgbUid: ");
+-		for(int i=0; i<16; ++i) {
+-			printf(" %2.2x", fooper1.rgbUid[i]);
+-		}
+-		printf("\n");
+-		
+-		printf("%.*s", level*3, spaces);
+-		printf(" w=%d mac=%d tag=0x%x size=%d cRef=%d foDelay=%x cbName=%x", fooper1.btWin32, fooper1.btMacOS, fooper1.tag , fooper1.size , fooper1.cRef , fooper1.foDelay, fooper1.cbName);
+-		if(fooper1.cbName) printf("name:");
+-		for(int i=0; i<fooper1.cbName; ++i) {
+-			printf(" %2.2x", *(BYTE *)(buf+off+i));
+-		}
+-		printf("\n");
+-		off += fooper1.cbName;
+-		
+-		printf(" dataLen=%ld\n", head.len - sizeof(fooper1) - fooper1.cbName);
+-		drawProc(buf, maxLen, &off, level+1);
+-
+-		
+-	}	break;
+-
+-
+-#if 0
+-	rgbUid (16 bytes): An MD4 message digest, as specified in [RFC1320], that specifies the unique identifier of the pixel data in the BLIP.
+-	tag (2 bytes): An unsigned integer that specifies an application-defined internal resource tag. This value MUST be 0xFF for external files.
+-	size (4 bytes): An unsigned integer that specifies the size, in bytes, of the BLIP in the stream.
+-	cRef (4 bytes): An unsigned integer that specifies the number of references to the BLIP. A value of 0x00000000 specifies an empty slot in the OfficeArtBStoreContainer record, as defined in section 2.2.20.
+-	foDelay (4 bytes): An MSOFO structure, as defined in section 2.1.4, that specifies the file offset into the associated OfficeArtBStoreDelay record, as defined in section 2.2.21, (delay stream). A value of 0xFFFFFFFF specifies that the file is not in the delay stream, and in this case, cRef MUST be 0x00000000.
+-	unused1 (1 byte): A value that is undefined and MUST be ignored.
+-	cbName (1 byte): An unsigned integer that specifies the length, in bytes, of the nameData field, including the terminating NULL character. This value MUST be an even number and less than or equal to 0xFE. If the value is 0x00, nameData will not be written.
+-	unused2 (1 byte): A value that is undefined and MUST be ignored.
+-	unused3 (1 byte): A value that is undefined and MUST be ignored.
+-	nameData (variable): A Unicode null-terminated string that specifies the name of the BLIP.
+-	embeddedBlip (variable): An OfficeArtBlip record, as defined in section 2.2.23, specifying the BLIP file data that is embedded in this record. If this value is not 0, foDelay MUST be ignored.
+-#endif
+-
+-	case 0xF008:
+-	{
+-		printf("OfficeArtFDG\n");
+-		dumpRec("OfficeArtFDG - spidCur needs to be set", &head, 0, NULL);
+-		struct {
+-			uint32_t	csp;
+-			uint32_t	spidCur;
+-		} fooper1;
+-		memcpy(&fooper1, buf+off, 8);
+-		off += 8;
+-		printf("%.*s", level*3, spaces);
+-		printf(" csp=%d spidCur=%d\n", fooper1.csp, fooper1.spidCur);
+-		
+-#if 0
+-		csp (4 bytes): An unsigned integer that specifies the number of shapes in this drawing.
+-		spidCur (4 bytes): An MSOSPID structure, as defined in section 2.1.2, that specifies the shape
+-		identifier of the last shape in this drawing.
+-#endif
+-		
+-	}	break;
+-
+-	case 0xF009:
+-	{
+-		printf("OfficeArtFSPGR\n");
+-		dumpRec("OfficeArtFSPGR", &head, head.len, buf+off);
+-		struct {
+-			int32_t	xLeft;
+-			int32_t	yTop;
+-			int32_t	xRight;
+-			int32_t	yBottom;
+-		} foo;
+-		memcpy(&foo, buf+off, 16);
+-		off += 16;
+-		printf("%.*s", level*3, spaces);
+-		printf(" l=%d t=%d r=%d b=%d\n", foo.xLeft, foo.yTop, foo.xRight, foo.yBottom);
+-	}	break;
+-
+-	case 0xF00A:	// OfficeArtFSP
+-	{
+-		printf("OfficeArtFSP\n");
+-		dumpRec("OfficeArtFSP", &head, 0, NULL);
+-		struct {
+-			uint32_t	spid;
+-			uint32_t	flags;
+-		} foo;
+-		memcpy(&foo, buf+off, 8);
+-		off += 8;
+-		printf("%.*s", level*3, spaces);
+-		printf(" SPID=%d flags=0x%x\n", foo.spid, foo.flags);
+-	}	break;
+-
+-	case 0xF00B:
+-	{
+-		printf("OfficeArtFOPT\n");
+-		dumpRec("OfficeArtFOPT", &head, head.len, buf+off);
+-		struct {
+-			//uint16_t blip : 1;
+-			//uint16_t complex : 1;
+-			uint16_t opid; // : 14
+-			uint32_t op;
+-		} foo;
+-		
+-		// OfficeArtFOPTE + complex
+-		for(int i=0; i<head.instance; ++i) {
+-			memcpy(&foo, buf+off, 6);
+-			off += 6;
+-			printf("%.*s", level*3, spaces);
+-			printf(" opid=0x%4.4X(%.5d) op=%8.8X\n", foo.opid, foo.opid, foo.op); // blip=%d complex=%d , foo.blip, foo.complex
+-			//printf("drawDataOPID(data, 0x%4.4X, 0x%8.8X);\n", foo.opid, foo.op);
+-		}
+-#if 0
+-          opid=80 op=000018AC(6316) Text ID
+-          opid=bf op=0000000A(10) fFitTextToShape
+-          opid=158 op=00000000(0) // Type of connection sites
+-          opid=181 op=00000800(2048) // fillColor
+-          opid=183 op=00000800(2048) // fillBackColor
+-          opid=1bf op=00000010(16) // hit test
+-          opid=23f op=00000003(3) // fshadowObscured
+-#endif
+-		int complex = head.len - head.instance * 6;
+-		if(complex) {
+-			printf("%.*s", level*3, spaces);
+-			printf(" complex:");
+-		
+-			for(int i=0; i<complex; ++i) {
+-				printf(" %2.2x", *(BYTE *)(buf+off+i));
+-			}
+-			printf("\n");
+-		}
+-		off += complex;
+-	}	break;
+-
+-	case 0xF00D:
+-		printf("msofbtClientTextbox\n");
+-		dumpRec("msofbtClientTextbox", &head, head.len, buf+off);
+-		break;
+-
+-	case 0xF010:
+-		printf("msofbtClientAnchor: ");
+-		dumpRec("msofbtClientAnchor", &head, head.len, buf+off);
+-		// https://code.google.com/p/excellibrary/source/browse/trunk/src/ExcelLibrary/Office/Excel/EscherRecords/MsofbtClientAnchor.cs?spec=svn18&r=18
+-		struct {
+-			uint16_t	Flag;
+-			uint16_t	Col1;
+-			uint16_t	DX1;
+-			uint16_t	Row1;
+-			uint16_t	DY1;
+-			uint16_t	Col2;
+-			uint16_t	DX2;
+-			uint16_t	Row2;
+-			uint16_t	DY2;
+-		} foo;
+-		memcpy(&foo, buf+off, 18);
+-		printf(" Flag=0x%2.2x Col1=0x%2.2x DX1=0x%2.2x Row1=0x%2.2x DY1=0x%2.2x Col2=0x%2.2x DX2=0x%2.2x Row2=0x%2.2x DY2=0x%2.2x \n",
+-			foo.Flag, foo.Col1, foo.DX1, foo.Row1, foo.DY1, foo.Col2, foo.DX2, foo.Row2, foo.DY2);
+-		off += head.len;
+-		break;
+-	case 0xF011:
+-		printf("msofbtClientData\n");
+-		dumpRec("msofbtClientData", &head, head.len, buf+off);
+-		off += head.len;
+-		break;
+-
+-	case 0xF01E:
+-	{	printf("OfficeArtBlipPNG\n");
+-		dumpRec("OfficeArtBlipPNG", &head, head.len, buf+off);
+-		struct {
+-			uint8_t		rgbUid1[16];
+-			uint16_t	tag;
+-		} foo;
+-		memcpy(&foo, buf+off, sizeof(foo));
+-		
+-		//off += sizeof(foo);
+-		printf("%.*s", level*3, spaces);
+-		printf(" rgbUid1: ");
+-		for(int i=0; i<16; ++i) {
+-			printf(" %2.2x", foo.rgbUid1[i]);
+-		}
+-		printf("\n");
+-		off += head.len;
+-	}	break;
+-
+-	case 0xF11E:
+-		printf("OfficeArtSplitMenuColorContainer: Array of colors\n");
+-		dumpRec("OfficeArtSplitMenuColorContainer", &head, head.len, buf+off);
+-		off += head.len;
+-		break;
+-
+-	case 0xF122:
+-	{	printf("OfficeArtTertiaryFOPT\n");
+-		struct {
+-			//uint16_t blip : 1;
+-			//uint16_t complex : 1;
+-			uint16_t opid; // : 14
+-			uint16_t op1;
+-			uint16_t op2;
+-		} foo;
+-		int count = head.len/6;
+-		printf("OfficeArtFOPT count=%d\n", count);
+-		dumpRec("OfficeArtTertiaryFOPT", &head, head.len, buf+off);
+-
+-		// OfficeArtFOPTE + complex
+-		for(int i=0; i<head.instance; ++i) {
+-			memcpy(&foo, buf+off, 6);
+-			off += 6;
+-			printf("%.*s", level*3, spaces);
+-			printf(" opid=0x%4.4X(%.5d) op1=%4.4X op1=%4.4X\n", foo.opid, foo.opid, foo.op1, foo.op2); // blip=%d complex=%d , foo.blip, foo.complex
+-		}
+-		//off += head.len;
+-	}	break;
+-
+-	default:
+-		printf("WTF ?!?!?!\n");
+-		//assert(!"Not Possible");
+-		off += head.len;
+-		break;
+-	}
+-
+-	*off_p = off;
+-	return head;
+-}
+-
+-static void dumpData(char *data);
+-static void dumpFunc(char *func);
+-
+-static void dumpRec(char *comment, struct drawHeader *h, int len, uint8_t *buf)
+-{
+-	int width = 0;
+-	static int num;
+-	char *tmp;
+-	
+-return;
+-
+-	if(len) {
+-		++num;
+-		//asprintf(&tmp, "// %s real len = %d\n", comment, h->len);
+-		asprintf(&tmp, "static unsigned char draw%03.3d[%d] = { ", num+sheetOffset, len);
+-		width = strlen(tmp);
+-		dumpData(tmp);
+-		
+-		for(int i=0; i<len; ++i) {
+-			asprintf(&tmp, "0x%02.2X, ", buf[i]);
+-			width += strlen(tmp);
+-			dumpData(tmp);
+-			
+-			if(width >= 79) {
+-				dumpData(strdup("\n    "));
+-				width = 4;
+-			}
+-		}
+-		dumpData(strdup("\n  };\n"));
+-	}
+-	
+-	char name[32];
+-	if(len) {
+-		sprintf(name, "draw%03.3d", num+sheetOffset);
+-	} else {
+-		strcpy(name, "NULL");
+-	}
+-
+-	asprintf(&tmp, "dumpDrawData(data,  0x%X, 0x%X, 0x%X, %u,  %d, %s /* len=%d */ ) ;  // %s\n", h->rec, h->instance, h->type, h->len, len, name, len, comment);
+-	dumpFunc(tmp);
+-}
+-
+-
+-static void dumpData(char *data)
+-{
+-	if(!formData) {
+-		formData = calloc(1,1);
+-	}
+-	
+-	char *oldStr = formData;
+-	asprintf(&formData, "%s%s", oldStr, data);
+-	free(oldStr);
+-	free(data);
+-}
+-static void dumpFunc(char *func)
+-{
+-	if(!formFunc) {
+-		formFunc = calloc(1,1);
+-	}
+-	
+-	char *oldStr = formFunc;
+-	asprintf(&formFunc, "%s%s", oldStr, func);
+-	free(oldStr);
+-}
+-
+-#if 0
+-static int finder(uint8_t *buf, uint32_t len, uint16_t pattern)
+-{
+-	int ret = 0;
+-	uint8_t b1 = pattern & 0xFF;
+-	uint8_t b2 = pattern >> 8;
+-	
+-	for(int i=0; i<(len-1); ++i) {
+-		if(buf[i] == b1 && buf[i+1] == b2) {
+-			printf("GOT FINDER HIT OFFSET %d\n", i);
+-			ret = 1;
+-		}
+-	}
+-	return ret;
+-}
+-
+-// MD4 open source: http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4 or
+-//                  http://www.opensource.apple.com/source/freeradius/freeradius-11/freeradius/src/lib/md4.c
+-// Size of TWIPS:   http://support.microsoft.com/kb/76388
+-#endif
+-
+-#pragma pack(pop)
+-
+-#endif
+-
+-
+-
+-
+-
+--- r-cran-readxl-0.1.1.orig/src/xlstool.c
++++ r-cran-readxl-0.1.1/src/xlstool.c
+@@ -1,32 +1,35 @@
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  *
+- * This file is part of libxls -- A multiplatform, C/C++ library
+- * for parsing Excel(TM) files.
++ * Copyright 2004 Komarov Valery
++ * Copyright 2006 Christophe Leitienne
++ * Copyright 2008-2017 David Hoerl
++ * Copyright 2013 Bob Colbert
++ * Copyright 2013-2018 Evan Miller
+  *
+- * Redistribution and use in source and binary forms, with or without modification, are
+- * permitted provided that the following conditions are met:
++ * This file is part of libxls -- A multiplatform, C/C++ library for parsing
++ * Excel(TM) files.
+  *
+- *    1. Redistributions of source code must retain the above copyright notice, this list of
+- *       conditions and the following disclaimer.
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
+  *
+- *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+- *       of conditions and the following disclaimer in the documentation and/or other materials
+- *       provided with the distribution.
++ *    1. Redistributions of source code must retain the above copyright notice,
++ *    this list of conditions and the following disclaimer.
+  *
+- * THIS SOFTWARE IS PROVIDED BY David Hoerl ''AS IS'' AND ANY EXPRESS OR IMPLIED
+- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David Hoerl OR
+- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *    2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
+  *
+- * Copyright 2004 Komarov Valery
+- * Copyright 2006 Christophe Leitienne
+- * Copyright 2013 Bob Colbert
+- * Copyright 2008-2013 David Hoerl
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS
++ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  */
+ 
+@@ -170,15 +173,18 @@ char *utf8_decode(const char *str, DWORD
+ 	return ret;
+ }
+ 
+-// Convert unicode string to to_enc encoding
+-char* unicode_decode(const char *s, size_t len, size_t *newlen, const char* to_enc)
+-{
+ #ifdef HAVE_ICONV
+-	// Do iconv conversion
+-#ifdef AIX
++static char* unicode_decode_iconv(const char *s, size_t len, size_t *newlen, const char* to_enc) {
++#if defined(_AIX) || defined(__sun)
+     const char *from_enc = "UTF-16le";
++    #define ICONV_CONST const
+ #else
+     const char *from_enc = "UTF-16LE";
++    #if defined(_WIN32)
++        #define ICONV_CONST const
++    #else
++        #define ICONV_CONST
++    #endif
+ #endif
+     char* outbuf = 0;
+ 
+@@ -220,7 +226,7 @@ char* unicode_decode(const char *s, size
+             out_ptr = outbuf;
+             while(inlenleft)
+             {
+-                st = iconv(ic, (char **)&src_ptr, &inlenleft, (char **)&out_ptr,(size_t *) &outlenleft);
++                st = iconv(ic, (ICONV_CONST char **)&src_ptr, &inlenleft, (char **)&out_ptr,(size_t *) &outlenleft);
+                 if(st == (size_t)(-1))
+                 {
+                     if(errno == E2BIG)
+@@ -256,46 +262,57 @@ char* unicode_decode(const char *s, size
+         }
+     }
+     return outbuf;
++}
++
+ #else
+-	// Do wcstombs conversion
+-	char *converted = NULL;
+-	int count, count2, i;
+-	wchar_t *w;
+-    short *x;
+-	if (setlocale(LC_CTYPE, "") == NULL) {
+-		printf("setlocale failed: %d\n", errno);
+-		return "*null*";
+-	}
+ 
+-    x=(short *)s;
++static char *unicode_decode_wcstombs(const char *s, size_t len, size_t *newlen) {
++	// Do wcstombs conversion
++    char *converted = NULL;
++    int count, count2;
++    size_t i;
++    wchar_t *w;
++    if (setlocale(LC_CTYPE, "") == NULL) {
++        printf("setlocale failed: %d\n", errno);
++        return NULL;
++    }
+ 
+     w = malloc((len/2+1)*sizeof(wchar_t));
+ 
+     for(i=0; i<len/2; i++)
+     {
+-        w[i]=xlsShortVal(x[i]);
++        w[i] = (BYTE)s[2*i] + ((BYTE)s[2*i+1] << 8);
+     }
+     w[len/2] = '\0';
+ 
+     count = wcstombs(NULL, w, 0);
+ 
+-	if (count <= 0) {
+-		if (newlen) *newlen = 0;
+-		free(w);
+-		return NULL;
+-	}
++    if (count <= 0) {
++        if (newlen) *newlen = 0;
++        free(w);
++        return NULL;
++    }
+ 
+-	converted = calloc(count+1, sizeof(char));
+-	count2 = wcstombs(converted, w, count);
++    converted = calloc(count+1, sizeof(char));
++    count2 = wcstombs(converted, w, count);
+     free(w);
+-	if (count2 <= 0) {
+-		printf("wcstombs failed (%d)\n", len/2);
+-		if (newlen) *newlen = 0;
+-		return converted;
+-	} else {
+-		if (newlen) *newlen = count2;
+-		return converted;
+-	}
++    if (count2 <= 0) {
++        printf("wcstombs failed (%lu)\n", (unsigned long)len/2);
++        if (newlen) *newlen = 0;
++        return converted;
++    }
++    if (newlen) *newlen = count2;
++    return converted;
++}
++#endif
++
++// Convert unicode string to to_enc encoding
++char* unicode_decode(const char *s, size_t len, size_t *newlen, const char* to_enc)
++{
++#ifdef HAVE_ICONV
++    return unicode_decode_iconv(s, len, newlen, to_enc);
++#else
++    return unicode_decode_wcstombs(s, len, newlen);
+ #endif
+ }
+ 
+@@ -313,7 +330,7 @@ char *get_string(const char *s, size_t l
+         if (ofs + 2 > len) {
+             return NULL;
+         }
+-        ln=xlsShortVal(*(WORD_UA *)str);
++        ln= ((BYTE*)str)[0] + (((BYTE*)str)[1] << 8);
+         ofs+=2;
+     } else {
+ 		// single byte length
+@@ -346,8 +363,7 @@ char *get_string(const char *s, size_t l
+         if (ofs + 2*ln > len) {
+             return NULL;
+         }
+-		size_t new_len = 0;
+-        ret = unicode_decode(str+ofs,ln*2, &new_len,charset);
++        ret = unicode_decode(str+ofs, ln*2, NULL, charset);
+     } else {
+         if (ofs + ln > len) {
+             return NULL;
+@@ -559,11 +575,11 @@ void xls_showXF(XF8* xf)
+     printf("GroundColor: 0x%x\n",xf->groundcolor);
+ }
+ 
+-char *xls_getfcell(xlsWorkBook* pWB, struct st_cell_data* cell, WORD *label)
++char *xls_getfcell(xlsWorkBook* pWB, struct st_cell_data* cell, BYTE *label)
+ {
+     struct st_xf_data *xf = NULL;
+ 	WORD	len = 0;
+-    WORD    offset = 0;
++    DWORD   offset = 0;
+     char	*ret = NULL;
+     size_t  retlen = 100;
+ 
+@@ -573,8 +589,11 @@ char *xls_getfcell(xlsWorkBook* pWB, str
+     switch (cell->id)
+     {
+     case XLS_RECORD_LABELSST:
+-		//printf("WORD: %u short: %u str: %s\n", *label, xlsShortVal(*label), pWB->sst.string[xlsIntVal(*label)].str );
+-        offset = xlsIntVal(*(DWORD *)label);
++        offset = label[0] + (label[1] << 8);
++        if(!pWB->is5ver) {
++            offset += ((DWORD)label[2] << 16);
++            offset += ((DWORD)label[3] << 24);
++        }
+         if(offset < pWB->sst.count && pWB->sst.string[offset].str) {
+             ret = strdup(pWB->sst.string[offset].str);
+         }
+@@ -584,19 +603,20 @@ char *xls_getfcell(xlsWorkBook* pWB, str
+         ret = strdup("");
+         break;
+     case XLS_RECORD_LABEL:
+-		len = xlsShortVal(*label);
+-        label++;
++        len = label[0] + (label[1] << 8);
++        label += 2;
+ 		if(pWB->is5ver) {
+             ret = malloc(len+1);
+             memcpy(ret, label, len);
+             ret[len] = 0;
+ 			//printf("Found BIFF5 string of len=%d \"%s\"\n", len, ret);
+-		} else if ((*(BYTE *)label & 0x01) == 0) {
+-			ret = utf8_decode((char *)label + 1, len, pWB->charset);
+ 		} else {
+-			size_t newlen;
+-		    ret = unicode_decode((char *)label + 1, len*2, &newlen, pWB->charset);
+-		}
++            if ((*(label++) & 0x01) == 0) {
++                ret = utf8_decode((char *)label, len, pWB->charset);
++            } else {
++                ret = unicode_decode((char *)label, len*2, NULL, pWB->charset);
++            }
++        }
+         break;
+     case XLS_RECORD_RK:
+     case XLS_RECORD_NUMBER:


Reply to: