packages feed

xls (empty) → 0.1.0

raw patch · 23 files changed

+5584/−0 lines, 23 filesdep +basedep +conduitdep +filepathsetup-changed

Dependencies added: base, conduit, filepath, getopt-generics, resourcet, transformers, xls

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Harendra Kumar (c) 2016++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * 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.++    * Neither the name of Harendra Kumar nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++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+OWNER 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.
+ README.md view
@@ -0,0 +1,41 @@+## Haskell xls Parsing++[![Build Status](https://travis-ci.org/harendra-kumar/xls.svg?branch=master)](https://travis-ci.org/harendra-kumar/xls)+[![Build status](https://ci.appveyor.com/api/projects/status/nwknaf0gw1p9vqnv?svg=true)](https://ci.appveyor.com/project/harendra-kumar/xls)++`xls` is a Haskell library to parse Microsoft Excel spreadsheet files. It+parses the xls file format (extension `.xls`) more specifically known as+`BIFF/Excel 97-2004`.++It can be useful for mining data from old Microsoft Excel spreadsheets.++## API+Use `decodeXls` to get a streaming Conduit. For example to convert an+xls file to comma separated csv:++```haskell+xlsToCSV :: String -> IO ()+xlsToCSV file =+      runResourceT+    $ decodeXls file+    $$ CL.mapM_ (liftIO . putStrLn . intercalate ",")+```++An `xls2csv` utility is shipped with the package.+See the [haddock+documentation](https://rawgit.com/harendra-kumar/xls/master/doc/index.html)+for the API details.++## Under the hood+The library is based on the C library libxls, see+[sourceforge](https://sourceforge.net/projects/libxls/) or+[github](https://github.com/svn2github/libxls).++## See Also++* [xlsior](https://hackage.haskell.org/package/xlsior): Streaming Excel (xslx) file generation and parsing+* [xlsx](https://hackage.haskell.org/package/xlsx): Excel xslx file parser/writer++## Contributing+Welcome! If you would like to have something changed or added go ahead,+raise an issue or send a pull request.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ bin/xls2csv.hs view
@@ -0,0 +1,20 @@+#!/usr/bin/env stack+-- stack --resolver lts runhaskell --package getopt-generics++import           Control.Monad.IO.Class+import           Control.Monad.Trans.Resource+import           Data.Conduit+import           Data.Conduit.List            as CL+import           Data.List                    (intercalate)+import           Data.Xls+import           WithCli++-- TODO need to escape the separator and the escaping quotes themselves++xlsToCSV :: String -> IO ()+xlsToCSV file =+      runResourceT+    $ decodeXls file+    $$ CL.mapM_ (liftIO . putStrLn . intercalate ",")++main = withCli xlsToCSV
+ lib/Data/Xls.hs view
@@ -0,0 +1,201 @@+-- |+-- Module      : Data.Xls+-- Copyright   : (c) 2016 Harendra Kumar+--+-- License     : BSD-style+-- Maintainer  : harendra.kumar@gmail.com+-- Stability   : experimental+-- Portability : GHC+--+-- Parse Microsoft excel spreadsheet xls file (format BIFF/Excel 97-2004).+--+{-# OPTIONS_GHC -pgmP gcc -optP -E -optP -undef -optP -std=c89 #-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE RankNTypes #-}+#if __GLASGOW_HASKELL__ < 7100+{-# LANGUAGE DeriveDataTypeable #-}+#endif++module Data.Xls (decodeXls, XlsException(..)) where++import           Control.Exception            (Exception, throwIO)+import           Control.Monad.IO.Class+import           Control.Monad.Trans.Resource+import           Data.Conduit                 hiding (Conduit, Sink, Source)+import           Data.Data+import           Data.Int+import           Data.Maybe                   (catMaybes, fromJust, isJust)+import           Foreign.C+import           Foreign.Ptr+import           Text.Printf++#define CCALL(name,signature) \+foreign import ccall unsafe #name \+    c_##name :: signature++-- Workbook accessor functions+data XLSWorkbookStruct+type XLSWorkbook = Ptr XLSWorkbookStruct++CCALL(xls_open,          CString -> CString -> IO XLSWorkbook)+CCALL(xls_wb_sheetcount, XLSWorkbook -> IO CInt -- Int32)+CCALL(xls_close_WB,      XLSWorkbook -> IO ())++-- Worksheet accessor functions+data XLSWorksheetStruct+type XLSWorksheet = Ptr XLSWorksheetStruct++CCALL(xls_getWorkSheet, XLSWorkbook -> CInt -> IO XLSWorksheet)++CCALL(xls_parseWorkSheet, XLSWorksheet -> IO ())+CCALL(xls_ws_rowcount,    XLSWorksheet -> IO Int16 -- Int16)+CCALL(xls_ws_colcount,    XLSWorksheet -> IO Int16 -- Int16)+CCALL(xls_close_WS,       XLSWorksheet -> IO ())++-- Cell accessor functions+data XLSCellStruct+type XLSCell = Ptr XLSCellStruct++CCALL(xls_cell, XLSWorksheet -> Int16 -> Int16 -> IO XLSCell)++CCALL(xls_cell_type,            XLSCell -> IO Int16 -- Int16)+CCALL(xls_cell_strval,          XLSCell -> IO CString)+CCALL(xls_cell_formulatype,     XLSCell -> IO Int32 -- Int32)+CCALL(xls_cell_numval,          XLSCell -> IO CDouble)+-- CCALL(xls_cell_colspan,         XLSCell -> IO Int16 -- Int16)+-- CCALL(xls_cell_rowspan,         XLSCell -> IO Int16 -- Int16)+CCALL(xls_cell_hidden,          XLSCell -> IO Int8 -- Int8)++data XlsException =+      XlsFileNotFound String+    | XlsParseError String+    deriving (Show, Typeable)++instance Exception XlsException++-- | Parse a Microsoft excel xls workbook file into a Conduit yielding+-- rows in a worksheet. Each row represented by a list of Strings, each String+-- representing an individual cell.+--+-- Currently there is no separation of worksheets, all worksheets in a+-- workbook get concatenated.+--+-- Throws 'XlsException'+--+decodeXls :: MonadResource m => FilePath -> Producer m [String]+decodeXls file =+    bracketP alloc cleanup decodeWorkSheets+    where+        alloc = do+            file' <- newCString file+            pWB <- newCString "UTF-8" >>= c_xls_open file'+            if pWB == nullPtr then+                throwIO $ XlsFileNotFound+                        $ "XLS file " ++ file ++ " not found."+            else+                return pWB++        cleanup = c_xls_close_WB++        decodeWorkSheets pWB = do+            count <- liftIO $ c_xls_wb_sheetcount pWB+            mapM_ (decodeOneWorkSheet file pWB) [0 .. count - 1]++decodeOneWorkSheet+    :: MonadResource m+    => FilePath -> XLSWorkbook -> CInt -> Producer m [String]+decodeOneWorkSheet file pWB index =+    bracketP alloc cleanup decodeWS+    where+        alloc = do+            pWS <- c_xls_getWorkSheet pWB index+            if pWS == nullPtr then+                throwIO $ XlsParseError+                        $ "XLS file " ++ file ++ " could not be parsed."+            else do+              c_xls_parseWorkSheet pWS+              return pWS++        cleanup = c_xls_close_WS++        decodeWS = decodeRows++decodeRows :: MonadResource m => XLSWorksheet -> Producer m [String]+decodeRows pWS = do+    rows <- liftIO $ c_xls_ws_rowcount pWS+    cols <- liftIO $ c_xls_ws_colcount pWS+    mapM_ (decodeOneRow pWS cols) [r | r <- [0 .. rows - 1]]++decodeOneRow+    :: MonadResource m+    => XLSWorksheet -> Int16 -> Int16 -> Producer m [String]+decodeOneRow pWS cols rowindex =+    mapM (liftIO . (c_xls_cell pWS rowindex)) [0 .. cols - 1]+        >>= mapM (liftIO. decodeOneCell)+        >>= yield . catMaybes++data CellType = Numerical | Formula | Str | Other++decodeOneCell :: XLSCell -> IO (Maybe String)+decodeOneCell cellPtr = do+    nil <- isNullCell cellPtr+    if nil then+        return Nothing+    else cellValue cellPtr >>= return . Just++    where+        isNullCell ptr =+            if ptr == nullPtr then+                return True+            else do+                hidden <- c_xls_cell_hidden ptr+                if hidden /= 0 then+                    return True+                else+                    return False++        cellValue ptr = do+            typ     <- c_xls_cell_type ptr+            numval  <- c_xls_cell_numval ptr+            ftype   <- c_xls_cell_formulatype ptr+            --rowspan <- c_xls_cell_rowspan ptr+            --colspan <- c_xls_cell_colspan ptr+            pStr    <- c_xls_cell_strval ptr+            strval  <-+                if pStr /= nullPtr then+                    peekCString pStr >>= return . Just+                else+                    return Nothing++            return $ case cellType typ ftype strval of+                Numerical   -> outputNum numval+                Formula     -> decodeFormula strval numval+                Str         -> fromJust strval+                Other       -> "" -- we don't decode anything else++        decodeFormula str numval =+            case str of+                Just "bool"  -> outputBool numval+                Just "error" -> "*error*"+                Just x       -> x+                Nothing      -> "" -- is it possible?++        outputNum  d = printf "%.15g" (uncurry encodeFloat (decodeFloat d)+                                       :: Double)+        outputBool d = if d == 0 then "false" else "true"++        cellType t ftype strval =+            if t == 0x27e || t == 0x0BD || t == 0x203 then+                Numerical+            else if t == 0x06 then+                if ftype == 0 then+                    Numerical+                else+                    Formula+            else if isJust strval then+                Str+            else+                Other
+ lib/libxls-wrapper.c view
@@ -0,0 +1,46 @@+#include "libxls/xls.h"++DWORD xls_wb_sheetcount (xlsWorkBook* pWB) {+    return pWB->sheets.count;+}++WORD xls_ws_rowcount (xlsWorkSheet* pWS) {+    return pWS->rows.lastrow + 1;+}++/*+ * The library seems to treat lastcol as index but it seems like it is a count+ * instead because the last column index always turns out to return a null cell+ */++WORD xls_ws_colcount (xlsWorkSheet* pWS) {+    return pWS->rows.lastcol;+}++WORD xls_cell_type (xlsCell *cell) {+    return cell->id;+}++BYTE * xls_cell_strval (xlsCell *cell) {+    return cell->str;+}++int32_t xls_cell_formulatype (xlsCell *cell) {+    return cell->l;+}++double xls_cell_numval (xlsCell *cell) {+    return cell->d;+}++WORD xls_cell_colspan (xlsCell *cell) {+    return cell->colspan;+}++WORD xls_cell_rowspan (xlsCell *cell) {+    return cell->rowspan;+}++BYTE xls_cell_hidden (xlsCell *cell) {+    return cell->isHidden;+}
+ lib/libxls/config/config.h view
@@ -0,0 +1,10 @@+/* Define to 1 if you have the `asprintf' function. */+#define HAVE_ASPRINTF 1++/* Define if you have the iconv() function. */+#if (!defined(__MINGW32__) && !defined(mingw32_HOST_OS)) || defined (FORCE_HAS_ICONV)+#define HAVE_ICONV 1+#endif++/* Define to the version of this package. */+#define PACKAGE_VERSION "1.4.0"
+ lib/libxls/include/libxls/brdb.c.h view
@@ -0,0 +1,213 @@+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *+ *+ * This file is part of libxls -- A multiplatform, C/C++ library+ * for parsing Excel(TM) files.+ *+ * Redistribution and use in source and binary forms, with or without modification, are+ * permitted provided that the following conditions are met:+ *+ *    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 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.+ *+ * Copyright 2004 Komarov Valery+ * Copyright 2006 Christophe Leitienne+ * Copyright 2008-2012 David Hoerl+ *+ */++{ 0x00, "Unknown",	""},+{ 0x06, "FORMULA",	"Cell Formula" },+{ 0x09, "BOF-BIFF2",	"Beginning of File" },+{ 0x0A, "EOF",	"End of File" },+{ 0x0C, "CALCCOUNT",	"Iteration Count" },+{ 0x0D, "CALCMODE",	"Calculation Mode" },+{ 0x0E, "PRECISION",	"Precision" },+{ 0x0F, "REFMODE",	"Reference Mode" },+{ 0x10, "DELTA",	"Iteration Increment" },+{ 0x11, "ITERATION",	"Iteration Mode" },+{ 0x12, "PROTECT",	"Protection Flag" },+{ 0x13, "PASSWORD",	"Protection Password" },+{ 0x14, "HEADER",	"Print Header on Each Page" },+{ 0x15, "FOOTER",	"Print Footer on Each Page" },+{ 0x16, "EXTERNCOUNT",	"Number of External References" },+{ 0x17, "EXTERNSHEET",	"External Reference" },+{ 0x18, "DEFINEDNAME",	"User Defined Formulas (and others)" },+{ 0x19, "?WINDOWPROTECT",	" (biffview guessed)" },+{ 0x1A, "VERTICALPAGEBREAKS",	"Explicit Column Page Breaks" },+{ 0x1B, "HORIZONTALPAGEBREAKS",	"Explicit Row Page Breaks" },+{ 0x1C, "NOTE",	"Comment Associated with a Cell" },+{ 0x1D, "SELECTION",	"Current Selection" },+{ 0x22, "DATEMODE",	"1904 Date System" },+{ 0x26, "LEFTMARGIN",	"Left Margin Measurement" },+{ 0x27, "RIGHTMARGIN",	"Right Margin Measurement" },+{ 0x28, "TOPMARGIN",	"Top Margin Measurement" },+{ 0x29, "BOTTOMMARGIN",	"Bottom Margin Measurement" },+{ 0x2A, "PRINTHEADERS",	"Print Row/Column Labels" },+{ 0x2B, "PRINTGRIDLINES",	"Print Gridlines Flag" },+{ 0x2F, "FILEPASS",	"File Is Password-Protected" },+{ 0x31, "FONT",	"Font Description" },+{ 0x3C, "CONTINUE",	"Continues Long Records" },+{ 0x3D, "WINDOW1",	"Window Information" },+{ 0x40, "BACKUP",	"Save Backup Version of the File" },+{ 0x41, "PANE",	"Number of Panes and Their Position" },+{ 0x42, "CODEPAGE",	"Default Code Page" },+{ 0x4D, "PLS",	"Environment-Specific Print Record" },+{ 0x50, "DCON",	"Data Consolidation Information" },+{ 0x51, "DCONREF",	"Data Consolidation References" },+{ 0x52, "DCONNAME",	"Data Consolidation Named References" },+{ 0x55, "DEFCOLWIDTH",	"Default Width for Columns" },+{ 0x59, "XCT",	"CRN Record Count" },+{ 0x5A, "CRN",	"Nonresident Operands" },+{ 0x5B, "FILESHARING",	"File-Sharing Information" },+{ 0x5C, "WRITEACCESS",	"Write Access User Name" },+{ 0x5D, "OBJ",	"Describes a Graphic Object" },+{ 0x5E, "UNCALCED",	"Recalculation Status" },+{ 0x5F, "SAVERECALC",	"Recalculate Before Save" },+{ 0x60, "TEMPLATE",	"Workbook Is a Template" },+{ 0x63, "OBJPROTECT",	"Objects Are Protected" },+{ 0x7D, "COLINFO",	"Column Formatting Information" },+{ 0x7F, "IMDATA",	"Image Data" },+{ 0x80, "GUTS",	"Size of Row and Column Gutters" },+{ 0x81, "WSBOOL",	"Additional Workspace Information" },+{ 0x82, "GRIDSET",	"State Change of Gridlines Option" },+{ 0x83, "HCENTER",	"Center Between Horizontal Margins" },+{ 0x84, "VCENTER",	"Center Between Vertical Margins" },+{ 0x85, "BOUNDSHEET",	"Sheet Information" },+{ 0x86, "WRITEPROT",	"Workbook Is Write-Protected" },+{ 0x87, "ADDIN",	"Workbook Is an Add-in Macro" },+{ 0x88, "EDG",	"Edition Globals" },+{ 0x89, "PUB",	"Publisher" },+{ 0x8C, "COUNTRY",	"Default Country and WIN.INI Country" },+{ 0x8D, "HIDEOBJ",	"Object Display Options" },+{ 0x90, "SORT",	"Sorting Options" },+{ 0x91, "SUB",	"Subscriber" },+{ 0x92, "PALETTE",	"Color Palette Definition" },+{ 0x94, "LHRECORD",	".WK? File Conversion Information" },+{ 0x95, "LHNGRAPH",	"Named Graph Information" },+{ 0x96, "SOUND",	"Sound Note" },+{ 0x99, "STANDARDWIDTH",	"Standard Column Width" },+{ 0x98, "LPR",	"Sheet Was Printed Using LINE.PRINT" },+{ 0x9A, "FNGROUPNAME",	"Function Group Name" },+{ 0x9B, "FILTERMODE",	"Sheet Contains Filtered List" },+{ 0x9C, "FNGROUPCOUNT",	"Built-in Function Group Count" },+{ 0x9D, "AUTOFILTERINFO",	"Drop-Down Arrow Count" },+{ 0x9E, "AUTOFILTER",	"AutoFilter Data" },+{ 0xA0, "SCL",	"Window Zoom Magnification" },+{ 0xA1, "SETUP",	"Page Setup" },+{ 0xA9, "COORDLIST",	"Polygon Object Vertex Coordinates" },+{ 0xAB, "GCW",	"Global Column-Width Flags" },+{ 0xAE, "SCENMAN",	"Scenario Output Data" },+{ 0xAF, "SCENARIO",	"Scenario Data" },+{ 0xB0, "SXVIEW",	"View Definition" },+{ 0xB1, "SXVD",	"View Fields" },+{ 0xB2, "SXVI",	"View Item" },+{ 0xB4, "SXIVD",	"Row/Column Field IDs" },+{ 0xB5, "SXLI",	"Line Item Array" },+{ 0xB6, "SXPI",	"Page Item" },+{ 0xB8, "DOCROUTE",	"Routing Slip Information" },+{ 0xB9, "RECIPNAME",	"Recipient Name" },+{ 0xBC, "SHRFMLA",	"Shared Formula" },+{ 0xBD, "MULRK",	"Multiple RK Cells" },+{ 0xBE, "MULBLANK",	"Multiple Blank Cells" },+{ 0xC1, "MMS",	"ADDMENU/DELMENU Record Group Count" },+{ 0xC2, "ADDMENU",	"Menu Addition" },+{ 0xC3, "DELMENU",	"Menu Deletion" },+{ 0xC5, "SXDI",	"Data Item" },+{ 0xC6, "SXDB",	"PivotTable Cache Data" },+{ 0xCD, "SXSTRING",	"String" },+{ 0xD0, "SXTBL",	"Multiple Consolidation Source Info" },+{ 0xD1, "SXTBRGIITM",	"Page Item Name Count" },+{ 0xD2, "SXTBPG",	"Page Item Indexes" },+{ 0xD3, "OBPROJ",	"Visual Basic Project" },+{ 0xD5, "SXIDSTM",	"Stream ID" },+{ 0xD6, "RSTRING",	"Cell with Character Formatting" },+{ 0xD7, "DBCELL",	"Stream Offsets" },+{ 0xDA, "BOOKBOOL",	"Workbook Option Flag" },+{ 0xDC, "PARAMQRY-SXEXT",	"Query Parameters-External Source Information" },+{ 0xDD, "SCENPROTECT",	"Scenario Protection" },+{ 0xDE, "OLESIZE",	"Size of OLE Object" },+{ 0xDF, "UDDESC",	"Description String for Chart Autoformat" },+{ 0xE0, "XF",	"Extended Format" },+{ 0xE1, "INTERFACEHDR",	"Beginning of User Interface Records" },+{ 0xE2, "INTERFACEEND",	"End of User Interface Records" },+{ 0xE3, "SXVS",	"View Source" },+{ 0xE5, "CSPAN",	"Cells span" },+{ 0xEA, "TABIDCONF",	"Sheet Tab ID of Conflict History" },+{ 0xEB, "MSODRAWINGGROUP",	"Microsoft Office Drawing Group" },+{ 0xEC, "MSODRAWING",	"Microsoft Office Drawing" },+{ 0xED, "MSODRAWINGSELECTION",	"Microsoft Office Drawing Selection" },+{ 0xEF, "PHONETIC-INFO", "Specifies the default format for phonetic strings " },+{ 0xF0, "SXRULE",	"PivotTable Rule Data" },+{ 0xF1, "SXEX",	"PivotTable View Extended Information" },+{ 0xF2, "SXFILT",	"PivotTable Rule Filter" },+{ 0xF6, "SXNAME",	"PivotTable Name" },+{ 0xF7, "SXSELECT",	"PivotTable Selection Information" },+{ 0xF8, "SXPAIR",	"PivotTable Name Pair" },+{ 0xF9, "SXFMLA",	"PivotTable Parsed Expression" },+{ 0xFB, "SXFORMAT",	"PivotTable Format Record" },+{ 0xFC, "SST",	"Shared String Table" },+{ 0xFD, "LABELSST",	"Cell Value, String Constant/SST" },+{ 0xFF, "EXTSST",	"Extended Shared String Table" },+{ 0x100, "SXVDEX",	"Extended PivotTable View Fields" },+{ 0x103, "SXFORMULA",	"PivotTable Formula Record" },+{ 0x122, "SXDBEX",	"PivotTable Cache Data" },+{ 0x13D, "TABID",	"Sheet Tab Index Array" },+{ 0x160, "USESELFS",	"Natural Language Formulas Flag" },+{ 0x161, "DSF",	"Double Stream File" },+{ 0x162, "XL5MODIFY",	"Flag for DSF" },+{ 0x1A5, "FILESHARING2",	"File-Sharing Information for Shared Lists" },+{ 0x1A9, "USERBVIEW",	"Workbook Custom View Settings" },+{ 0x1AA, "USERSVIEWBEGIN",	"Custom View Settings" },+{ 0x1AB, "USERSVIEWEND",	"End of Custom View Records" },+{ 0x1AD, "QSI",	"External Data Range" },+{ 0x1AE, "SUPBOOK",	"Supporting Workbook" },+{ 0x1AF, "PROT4REV",	"Shared Workbook Protection Flag" },+{ 0x1B0, "CONDFMT",	"Conditional Formatting Range Information" },+{ 0x1B1, "CF",	"Conditional Formatting Conditions" },+{ 0x1B2, "DVAL",	"Data Validation Information" },+{ 0x1B5, "DCONBIN",	"Data Consolidation Information" },+{ 0x1B6, "TXO",	"Text Object" },+{ 0x1B7, "REFRESHALL",	"Refresh Flag" },+{ 0x1B8, "HLINK",	"Hyperlink" },+{ 0x1BA, "CODENAME",	"Name of a workbook object," },+{ 0x1BB, "SXFDBTYPE",	"SQL Datatype Identifier" },+{ 0x1BC, "PROT4REVPASS",	"Shared Workbook Protection Password" },+{ 0x1BE, "DV",	"Data Validation Criteria" },+{ 0x1C1, "RECALC_ID", "identifier of the recalculation engine" },+{ 0x200, "DIMENSIONS",	"Cell Table Size" },+{ 0x201, "BLANK",	"Cell Value, Blank Cell" },+{ 0x203, "NUMBER",	"Cell Value, Floating-Point Number" },+{ 0x204, "LABEL",	"Cell Value, String Constant" },+{ 0x205, "BOOLERR",	"Cell Value, Boolean or Error" },+{ 0x207, "STRING",	"String Value of a Formula" },+{ 0x208, "ROW",	"Describes a Row" },+{ 0x209, "BOF-BIFF3",	"Beginning of File" },+{ 0x20B, "INDEX",	"Index Record" },+{ 0x218, "NAME",	"Defined Name" },+{ 0x221, "ARRAY",	"Array-Entered Formula" },+{ 0x223, "EXTERNNAME",	"Externally Referenced Name" },+{ 0x225, "DEFAULTROWHEIGHT",	"Default Row Height" },+{ 0x236, "TABLE",	"Data Table" },+{ 0x23E, "WINDOW2",	"Sheet Window Information" },+{ 0x27E, "RK",	"Cell Value, RK Number" },+{ 0x293, "STYLE",	"Style Information" },+{ 0x409, "BOF-BIFF4",	"Beginning of File" },+{ 0x41E, "FORMAT",	"Number Format" },+{ 0x4BC, "?FORMULA-RELATED=?(BC=SHRFMLA))",	"Formula related, always before there are 0x06 (FORMULA)" },+{ 0x809, "BOF-BIFF5/7/8",	"Beginning of File" },+{ 0x863, "BOOKEXT", "Specifies properties of a workbook file." },+{ 0xFFF, "",	"" },
+ lib/libxls/include/libxls/brdb.h view
@@ -0,0 +1,58 @@+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *+ *+ * This file is part of libxls -- A multiplatform, C/C++ library+ * for parsing Excel(TM) files.+ *+ * Redistribution and use in source and binary forms, with or without modification, are+ * permitted provided that the following conditions are met:+ *+ *    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 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.+ *+ * Copyright 2004 Komarov Valery+ * Copyright 2006 Christophe Leitienne+ * Copyright 2008-2012 David Hoerl+ *+ */++struct str_brdb+{+    WORD opcode;+    char * name;			/* printable name */+    char * desc;			/* printable description */+};+typedef struct str_brdb record_brdb;++record_brdb brdb[] =+    {+#include <libxls/brdb.c.h>+    };++static int get_brbdnum(int id)+{++    int i;+    i=0;+    do+    {+        if (brdb[i].opcode==id)+            return i;+        i++;+    }+    while (brdb[i].opcode!=0xFFF);+    return 0;+}
+ lib/libxls/include/libxls/endian.h view
@@ -0,0 +1,62 @@+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *+ *+ * This file is part of libxls -- A multiplatform, C/C++ library+ * for parsing Excel(TM) files.+ *+ * Redistribution and use in source and binary forms, with or without modification, are+ * permitted provided that the following conditions are met:+ *+ *    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 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.+ *+ * Copyright 2013 Bob Colbert+ *+ */++#include <libxls/xlsstruct.h>++int xls_is_bigendian();+DWORD xlsIntVal (DWORD i);+unsigned short xlsShortVal (short s);++void xlsConvertHeader(OLE2Header *h);+void xlsConvertPss(PSS* pss);++void xlsConvertDouble(BYTE *d);+void xlsConvertBof(BOF *b);+void xlsConvertBiff(BIFF *b);+void xlsConvertWindow(WIND1 *w);+void xlsConvertSst(SST *s);+void xlsConvertXf5(XF5 *x);+void xlsConvertXf8(XF8 *x);+void xlsConvertFont(FONT *f);+void xlsConvertFormat(FORMAT *f);+void xlsConvertBoundsheet(BOUNDSHEET *b);+void xlsConvertColinfo(COLINFO *c);+void xlsConvertRow(ROW *r);+void xlsConvertMergedcells(MERGEDCELLS *m);+void xlsConvertCol(COL *c);+void xlsConvertFormula(FORMULA *f);+void xlsConvertFormulaArray(FARRAY *f);+void xlsConvertHeader(OLE2Header *h);+void xlsConvertPss(PSS* pss);+#if 0 // unused+void xlsConvertUnicode(wchar_t *w, char *s, int len);+#endif++#define W_ENDIAN(a) a=xlsShortVal(a)+#define D_ENDIAN(a) a=xlsIntVal(a)
+ lib/libxls/include/libxls/ole.h view
@@ -0,0 +1,173 @@+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *+ *+ * This file is part of libxls -- A multiplatform, C/C++ library+ * for parsing Excel(TM) files.+ *+ * Redistribution and use in source and binary forms, with or without modification, are+ * permitted provided that the following conditions are met:+ *+ *    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 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.+ *+ * Copyright 2004 Komarov Valery+ * Copyright 2006 Christophe Leitienne+ * Copyright 2013 Bob Colbert+ * Copyright 2008-2013 David Hoerl+ *+ */++#ifndef OLE_INCLUDE+#define OLE_INCLUDE++#include <stdio.h>			// FILE *++#include "libxls/xlstypes.h"++#ifdef AIX+#pragma pack(1)+#else+#pragma pack(push, 1)+#endif++typedef struct TIME_T+{+    DWORD	LowDate;+    DWORD	HighDate;+}+TIME_T;++typedef struct OLE2Header+{+    DWORD		id[2];		//D0CF11E0 A1B11AE1+    DWORD		clid[4];+    WORD		verminor;	//0x3e+    WORD		verdll;		//0x03+    WORD		byteorder;+    WORD		lsectorB;+    WORD		lssectorB;++    WORD		reserved1;+    DWORD		reserved2;+    DWORD		reserved3;++    DWORD		cfat;			// count full sectors+    DWORD		dirstart;++    DWORD		reserved4;++    DWORD		sectorcutoff;	// min size of a standard stream ; if less than this then it uses short-streams+    DWORD		sfatstart;		// first short-sector or EOC+    DWORD		csfat;			// count short sectors+    DWORD		difstart;		// first sector master sector table or EOC+    DWORD		cdif;			// total count+    DWORD		MSAT[109];		// First 109 MSAT+}+OLE2Header;++#pragma pack(pop)++//-----------------------------------------------------------------------------------+typedef	struct st_olefiles+{+    long count;+    struct st_olefiles_data+    {+        BYTE*	name;+        DWORD	start;+        DWORD	size;+   }+    * file;+}+st_olefiles;++typedef struct OLE2+{+    FILE*		file;+    WORD		lsector;+    WORD		lssector;+    DWORD		cfat;+    DWORD		dirstart;++    DWORD		sectorcutoff;+    DWORD		sfatstart;+    DWORD		csfat;+    DWORD		difstart;+    DWORD		cdif;+    DWORD*		SecID;	// regular sector data+	DWORD*		SSecID;	// short sector data+	BYTE*		SSAT;	// directory of short sectors+    st_olefiles	files;+}+OLE2;++typedef struct OLE2Stream+{+    OLE2*	ole;+    DWORD	start;+    size_t	pos;+    size_t	cfat;+    size_t	size;+    size_t	fatpos;+    BYTE*	buf;+    DWORD	bufsize;+    BYTE	eof;+	BYTE	sfat;	// short+}+OLE2Stream;++#ifdef AIX+#pragma pack(1)+#else+#pragma pack(push, 1)+#endif++typedef struct PSS+{+    BYTE	name[64];+    WORD	bsize;+    BYTE	type;		//STGTY+#define PS_EMPTY		00+#define PS_USER_STORAGE	01+#define PS_USER_STREAM	02+#define PS_USER_ROOT	05+    BYTE	flag;		//COLOR+#define BLACK	1+    DWORD	left;+    DWORD	right;+    DWORD	child;+    WORD	guid[8];+    DWORD	userflags;+    TIME_T	time[2];+    DWORD	sstart;+    DWORD	size;+    DWORD	proptype;+}+PSS;++#pragma pack(pop)++extern size_t ole2_read(void* buf,size_t size,size_t count,OLE2Stream* olest);+extern OLE2Stream* ole2_sopen(OLE2* ole,DWORD start, size_t size);+extern void ole2_seek(OLE2Stream* olest,DWORD ofs);+extern OLE2Stream*  ole2_fopen(OLE2* ole,BYTE* file);+extern void ole2_fclose(OLE2Stream* ole2st);+extern OLE2* ole2_open(const BYTE *file);+extern void ole2_close(OLE2* ole2);+extern void ole2_bufread(OLE2Stream* olest);+++#endif
+ lib/libxls/include/libxls/xls.h view
@@ -0,0 +1,73 @@+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *+ *+ * This file is part of libxls -- A multiplatform, C/C++ library+ * for parsing Excel(TM) files.+ *+ * Redistribution and use in source and binary forms, with or without modification, are+ * permitted provided that the following conditions are met:+ *+ *    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 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.+ *+ * Copyright 2004 Komarov Valery+ * Copyright 2006 Christophe Leitienne+ * Copyright 2008-2012 David Hoerl+ *+ */++#ifndef XLS_INCLUDE+#define XLS_INCLUDE+ +#ifdef __cplusplus+namespace xls {+extern "C" {+#endif++#include "libxls/xlstypes.h"+#include "libxls/xlsstruct.h"+#include "libxls/xlstool.h"+++extern const char* xls_getVersion(void);++extern int xls(int debug);	// Set debug. Force library to load?+extern void xls_set_formula_hander(xls_formula_handler handler);++extern void xls_parseWorkBook(xlsWorkBook* pWB);+extern void xls_parseWorkSheet(xlsWorkSheet* pWS);++extern xlsWorkBook* xls_open(const char *file,const char *charset);	// convert 16bit strings within the spread sheet to this 8-bit encoding (UTF-8 default)+#define xls_close xls_close_WB                  // historical+extern void xls_close_WB(xlsWorkBook* pWB);     // preferred name++extern xlsWorkSheet * xls_getWorkSheet(xlsWorkBook* pWB,int num);+extern void xls_close_WS(xlsWorkSheet* pWS);++extern xlsSummaryInfo *xls_summaryInfo(xlsWorkBook* pWB);+extern void xls_close_summaryInfo(xlsSummaryInfo *pSI);++// utility function+xlsRow *xls_row(xlsWorkSheet* pWS, WORD cellRow);+xlsCell	*xls_cell(xlsWorkSheet* pWS, WORD cellRow, WORD cellCol);++#ifdef __cplusplus+} // extern c block+} // namespace+#endif++#endif+
+ lib/libxls/include/libxls/xlsstruct.h view
@@ -0,0 +1,534 @@+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *+ *+ * This file is part of libxls -- A multiplatform, C/C++ library+ * for parsing Excel(TM) files.+ *+ * Redistribution and use in source and binary forms, with or without modification, are+ * permitted provided that the following conditions are met:+ *+ *    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 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.+ *+ * Copyright 2004 Komarov Valery+ * Copyright 2006 Christophe Leitienne+ * Copyright 2013 Bob Colbert+ * Copyright 2008-2013 David Hoerl+ *+ */++#ifndef XLS_STRUCT_INC+#define XLS_STRUCT_INC++#include "libxls/ole.h"++#define XLS_RECORD_EOF          0x000A+#define XLS_RECORD_DEFINEDNAME  0x0018+#define XLS_RECORD_NOTE         0x001C+#define XLS_RECORD_1904         0x0022+#define XLS_RECORD_CONTINUE     0x003C+#define XLS_RECORD_WINDOW1      0x003D+#define XLS_RECORD_CODEPAGE     0x0042+#define XLS_RECORD_OBJ          0x005D+#define XLS_RECORD_MERGEDCELLS  0x00E5+#define XLS_RECORD_DEFCOLWIDTH  0x0055+#define XLS_RECORD_COLINFO      0x007D+#define XLS_RECORD_BOUNDSHEET   0x0085+#define XLS_RECORD_PALETTE      0x0092+#define XLS_RECORD_MULRK        0x00BD+#define XLS_RECORD_MULBLANK     0x00BE+#define XLS_RECORD_DBCELL       0x00D7+#define XLS_RECORD_XF           0x00E0+#define XLS_RECORD_MSODRAWINGGROUP   0x00EB+#define XLS_RECORD_MSODRAWING   0x00EC+#define XLS_RECORD_SST          0x00FC+#define XLS_RECORD_LABELSST     0x00FD+#define XLS_RECORD_EXTSST       0x00FF+#define XLS_RECORD_TXO          0x01B6+#define XLS_RECORD_HYPERREF     0x01B8+#define XLS_RECORD_BLANK        0x0201+#define XLS_RECORD_NUMBER       0x0203+#define XLS_RECORD_LABEL        0x0204+#define XLS_RECORD_BOOLERR      0x0205+#define XLS_RECORD_STRING       0x0207 // only follows a formula+#define XLS_RECORD_ROW          0x0208+#define XLS_RECORD_INDEX        0x020B+#define XLS_RECORD_ARRAY        0x0221 // Array-entered formula+#define XLS_RECORD_DEFAULTROWHEIGHT    0x0225+#define XLS_RECORD_FONT         0x0031 // spec says 0x0231 but Excel expects 0x0031+#define XLS_RECORD_FONT_ALT     0x0231+#define XLS_RECORD_WINDOW2      0x023E+#define XLS_RECORD_RK           0x027E+#define XLS_RECORD_STYLE        0x0293+#define XLS_RECORD_FORMULA      0x0006+#define XLS_RECORD_FORMULA_ALT  0x0406 // Apple Numbers bug+#define XLS_RECORD_FORMAT       0x041E+#define XLS_RECORD_BOF          0x0809++#define BLANK_CELL  XLS_RECORD_BLANK  // compat++#ifdef AIX+#pragma pack(1)+#else+#pragma pack(push, 1)+#endif++typedef struct BOF+{+    WORD id;+    WORD size;+}+BOF;++typedef struct BIFF+{+    WORD ver;+    WORD type;+    WORD id_make;+    WORD year;+    DWORD flags;+    DWORD min_ver;+    BYTE buf[100];+}+BIFF;++typedef struct WIND1+{+    WORD xWn;+    WORD yWn;+    WORD dxWn;+    WORD dyWn;+    WORD grbit;+    WORD itabCur;+    WORD itabFirst;+    WORD ctabSel;+    WORD wTabRatio;+}+WIND1;++typedef struct BOUNDSHEET+{+    DWORD	filepos;+    BYTE	type;+    BYTE	visible;+    BYTE	name[];+}+BOUNDSHEET;++typedef struct ROW+{+    WORD	index;+    WORD	fcell;+    WORD	lcell;+    WORD	height;+    WORD	notused;+    WORD	notused2; //used only for BIFF3-4+    WORD	flags;+    WORD	xf;+}+ROW;++typedef struct COL+{+    WORD	row;+    WORD	col;+    WORD	xf;+}+COL;+++typedef struct FORMULA // BIFF8+{+    WORD	row;+    WORD	col;+    WORD	xf;+	// next 8 bytes either a IEEE double, or encoded on a byte basis+    BYTE	resid;+    BYTE	resdata[5];+    WORD	res;+    WORD	flags;+    BYTE	chn[4]; // BIFF8+    WORD	len;+    BYTE	value[1]; //var+}+FORMULA;++typedef struct FARRAY // BIFF8+{+    WORD	row1;+    WORD	row2;+    BYTE	col1;+    BYTE	col2;+    WORD	flags;+    BYTE	chn[4]; // BIFF8+    WORD	len;+    BYTE	value[1]; //var+}+FARRAY;++typedef struct RK+{+    WORD	row;+    WORD	col;+    WORD	xf;+    DWORD_UA value;+}+RK;++typedef struct MULRK+{+    WORD	row;+    WORD	col;+	struct {+		WORD	xf;+		DWORD_UA value;+	}		rk[];+	//WORD	last_col;+}+MULRK;++typedef struct MULBLANK+{+    WORD	row;+    WORD	col;+    WORD	xf[];+	//WORD	last_col;+}+MULBLANK;++typedef struct BLANK+{+    WORD	row;+    WORD	col;+    WORD	xf;+}+BLANK;++typedef struct LABEL+{+    WORD	row;+    WORD	col;+    WORD	xf;+    BYTE	value[1]; // var+}+LABEL;+typedef LABEL LABELSST;++typedef struct BOOLERR+{+    WORD    row;+    WORD    col;+    WORD    xf;+    BYTE    value;+    BYTE    iserror;+}+BOOLERR;++typedef struct SST+{+    DWORD	num;+    DWORD	numofstr;+    BYTE	strings;+}+SST;++typedef struct XF5+{+    WORD	font;+    WORD	format;+    WORD	type;+    WORD	align;+    WORD	color;+    WORD	fill;+    WORD	border;+    WORD	linestyle;+}+XF5;++typedef struct XF8+{+    WORD	font;+    WORD	format;+    WORD	type;+    BYTE	align;+    BYTE	rotation;+    BYTE	ident;+    BYTE	usedattr;+    DWORD	linestyle;+    DWORD	linecolor;+    WORD	groundcolor;+}+XF8;++typedef struct BR_NUMBER+{+    WORD	row;+    WORD	col;+    WORD	xf;+    double value;+}+BR_NUMBER;++typedef struct COLINFO+{+    WORD	first;+    WORD	last;+    WORD	width;+    WORD	xf;+    WORD	flags;+    WORD	notused;+}+COLINFO;++typedef struct MERGEDCELLS+{+    WORD	rowf;+    WORD	rowl;+    WORD	colf;+    WORD	coll;+}+MERGEDCELLS;++typedef struct FONT+{+    WORD	height;+    WORD	flag;+    WORD	color;+    WORD	bold;+    WORD	escapement;+    BYTE	underline;+    BYTE	family;+    BYTE	charset;+    BYTE	notused;+    BYTE	name;+}+FONT;++typedef struct FORMAT+{+    WORD	index;+    BYTE	value[0];+}+FORMAT;++#pragma pack(pop)++//---------------------------------------------------------++typedef	struct st_sheet+{+    DWORD count;        // Count of sheets+    struct st_sheet_data+    {+        DWORD filepos;+        BYTE visibility;+        BYTE type;+        BYTE* name;+    }+    * sheet;+}+st_sheet;++typedef	struct st_font+{+    DWORD count;		// Count of FONT's+    struct st_font_data+    {+        WORD	height;+        WORD	flag;+        WORD	color;+        WORD	bold;+        WORD	escapement;+        BYTE	underline;+        BYTE	family;+        BYTE	charset;+        BYTE*	name;+    }+    * font;+}+st_font;++typedef struct st_format+{+    DWORD count;		// Count of FORMAT's+    struct st_format_data+    {+         WORD index;+         BYTE *value;+    }+    * format;+}+st_format;++typedef	struct st_xf+{+    DWORD count;	// Count of XF+    //	XF** xf;+    struct st_xf_data+    {+        WORD	font;+        WORD	format;+        WORD	type;+        BYTE	align;+        BYTE	rotation;+        BYTE	ident;+        BYTE	usedattr;+        DWORD	linestyle;+        DWORD	linecolor;+        WORD	groundcolor;+    }+    * xf;+}+st_xf;+++typedef	struct st_sst+{+    DWORD count;+    DWORD lastid;+    DWORD continued;+    DWORD lastln;+    DWORD lastrt;+    DWORD lastsz;+    struct str_sst_string+    {+        BYTE* str;+    }+    * string;+}+st_sst;+++typedef	struct st_cell+{+    DWORD count;+    struct st_cell_data+    {+        WORD	id;+        WORD	row;+        WORD	col;+        WORD	xf;+        BYTE*	str;		// String value;+        double	d;+        int32_t	l;+        WORD	width;		// Width of col+        WORD	colspan;+        WORD	rowspan;+        BYTE	isHidden;	// Is cell hidden+    }+    * cell;+}+st_cell;+++typedef	struct st_row+{+    //	DWORD count;+    WORD lastcol;	// numCols - 1+    WORD lastrow;	// numRows - 1+    struct st_row_data+    {+        WORD index;+        WORD fcell;+        WORD lcell;+        WORD height;+        WORD flags;+        WORD xf;+        BYTE xfflags;+        st_cell cells;+    }+    * row;+}+st_row;+++typedef	struct st_colinfo+{+    DWORD count;				// Count of COLINFO+    struct st_colinfo_data+    {+        WORD	first;+        WORD	last;+        WORD	width;+        WORD	xf;+        WORD	flags;+    }+    * col;+}+st_colinfo;++typedef struct xlsWorkBook+{+    //FILE*		file;+    OLE2Stream*	olestr;+    int32_t		filepos;		// position in file++    //From Header (BIFF)+    BYTE		is5ver;+    BYTE		is1904;+    WORD		type;+    WORD		activeSheetIdx;	// index of the active sheet++    //Other data+    WORD		codepage;		// Charset codepage+    char*		charset;+    st_sheet	sheets;+    st_sst		sst;			// SST table+    st_xf		xfs;			// XF table+    st_font		fonts;+    st_format	formats;		// FORMAT table++	char		*summary;		// ole file+	char		*docSummary;	// ole file+}+xlsWorkBook;++typedef struct xlsWorkSheet+{+    DWORD		filepos;+    WORD		defcolwidth;+    st_row		rows;+    xlsWorkBook *workbook;+    st_colinfo	colinfo;+}+xlsWorkSheet;++#ifdef __cplusplus+typedef struct st_cell::st_cell_data xlsCell;+typedef	struct st_row::st_row_data xlsRow;+#else+typedef struct st_cell_data xlsCell;+typedef	struct st_row_data xlsRow;+#endif++typedef struct xls_summaryInfo+{+	BYTE		*title;+	BYTE		*subject;+	BYTE		*author;+	BYTE		*keywords;+	BYTE		*comment;+	BYTE		*lastAuthor;+	BYTE		*appName;+	BYTE		*category;+	BYTE		*manager;+	BYTE		*company;+}+xlsSummaryInfo;++typedef void (*xls_formula_handler)(WORD bof, WORD len, BYTE *formula);++#endif
+ lib/libxls/include/libxls/xlstool.h view
@@ -0,0 +1,52 @@+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *+ *+ * This file is part of libxls -- A multiplatform, C/C++ library+ * for parsing Excel(TM) files.+ *+ * Redistribution and use in source and binary forms, with or without modification, are+ * permitted provided that the following conditions are met:+ *+ *    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 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.+ *+ * Copyright 2004 Komarov Valery+ * Copyright 2006 Christophe Leitienne+ * Copyright 2013 Bob Colbert+ * Copyright 2008-2013 David Hoerl+ *+ */++#include "libxls/xlsstruct.h"++extern void dumpbuf(BYTE* fname,long size,BYTE* buf);+extern void verbose(char* str);++extern BYTE *utf8_decode(BYTE *str, DWORD len, char *encoding);+extern BYTE* unicode_decode(const BYTE *s, int len, size_t *newlen, const char* encoding);+extern BYTE* get_string(BYTE *s,BYTE is2, BYTE isUnicode, char *charset);+extern DWORD xls_getColor(const WORD color,WORD def);++extern void xls_showBookInfo(xlsWorkBook* pWB);+extern void xls_showROW(struct st_row_data* row);+extern void xls_showColinfo(struct st_colinfo_data* col);+extern void xls_showCell(struct st_cell_data* 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 BYTE* xls_getfcell(xlsWorkBook* pWB,struct st_cell_data* cell,WORD *label);+extern char* xls_getCSS(xlsWorkBook* pWB);+extern void xls_showBOF(BOF* bof);
+ lib/libxls/include/libxls/xlstypes.h view
@@ -0,0 +1,70 @@+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *+ *+ * This file is part of libxls -- A multiplatform, C/C++ library+ * for parsing Excel(TM) files.+ *+ * Redistribution and use in source and binary forms, with or without modification, are+ * permitted provided that the following conditions are met:+ *+ *    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 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.+ *+ * Copyright 2004 Komarov Valery+ * Copyright 2006 Christophe Leitienne+ * Copyright 2013 Bob Colbert+ * Copyright 2008-2013 David Hoerl+ *+ */++#ifndef XLS_TYPES_INC+#define XLS_TYPES_INC++#include <stdint.h>++typedef unsigned char		BYTE;+typedef uint16_t			WORD;+typedef uint32_t			DWORD;++#ifdef NO_ALIGN+typedef uint16_t			WORD_UA;+typedef uint32_t			DWORD_UA;+#else+typedef uint16_t			WORD_UA		__attribute__ ((aligned (1)));	// 2 bytes+typedef uint32_t			DWORD_UA	__attribute__ ((aligned (1)));	// 4 bytes+#endif++// Windows+#if defined(_MSC_VER) && defined(WIN32)++typedef unsigned __int64	unsigned64_t;++// not windows+#else++#if defined(_UINT64_T)++typedef uint64_t			unsigned64_t;++#else++typedef unsigned long long	unsigned64_t;++// _UINT64_T+#endif+#endif++#endif
+ lib/libxls/src/endian.c view
@@ -0,0 +1,315 @@+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *+ *+ * This file is part of libxls -- A multiplatform, C/C++ library+ * for parsing Excel(TM) files.+ *+ * Redistribution and use in source and binary forms, with or without modification, are+ * permitted provided that the following conditions are met:+ *+ *    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 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.+ *+ * Copyright 2013 Bob Colbert+ *+ */++#include <stdlib.h>++#include "libxls/xlstypes.h"+#include "libxls/endian.h"+#include "libxls/ole.h"++int xls_is_bigendian()+{+#if defined (__BIG_ENDIAN__)+    return 1;+#elif defined (__LITTLE_ENDIAN__)+    return 0;+#else+#warning NO ENDIAN+    static int n = 1;++    if (*(char *)&n == 1)+    {+        return 0;+    }+    else+    {+        return 1;+    }+#endif+}++DWORD xlsIntVal (DWORD i)+{+    unsigned char c1, c2, c3, c4;++    if (xls_is_bigendian()) {+        c1 = i & 255;+        c2 = (i >> 8) & 255;+        c3 = (i >> 16) & 255;+        c4 = (i >> 24) & 255;++        return ((int)c1 << 24) + ((int)c2 << 16) + ((int)c3 << 8) + c4;+    } else {+        return i;+    }+}++unsigned short xlsShortVal (short s)+{+    unsigned char c1, c2;+    +    if (xls_is_bigendian()) {+        c1 = s & 255;+        c2 = (s >> 8) & 255;+    +        return (c1 << 8) + c2;+    } else {+        return s;+    }+}++void xlsConvertDouble(unsigned char *d)+{+    unsigned char t;+    int i;++    if (xls_is_bigendian()) {+        for (i=0; i<4; i++)+        {+            t = d[7-i];+            d[8-i] = d[i];+            d[i] = t;+        }+    }+}++void xlsConvertBof(BOF *b)+{+    b->id = xlsShortVal(b->id);+    b->size = xlsShortVal(b->size);+}++void xlsConvertBiff(BIFF *b)+{+    b->ver = xlsShortVal(b->ver);+    b->type = xlsShortVal(b->type);+    b->id_make = xlsShortVal(b->id_make);+    b->year = xlsShortVal(b->year);+    b->flags = xlsIntVal(b->flags);+    b->min_ver = xlsIntVal(b->min_ver);+}++void xlsConvertWindow(WIND1 *w)+{+    w->xWn = xlsShortVal(w->xWn);+    w->yWn = xlsShortVal(w->yWn);+    w->dxWn = xlsShortVal(w->dxWn);+    w->dyWn = xlsShortVal(w->dyWn);+    w->grbit = xlsShortVal(w->grbit);+    w->itabCur = xlsShortVal(w->itabCur);+    w->itabFirst = xlsShortVal(w->itabFirst);+    w->ctabSel = xlsShortVal(w->ctabSel);+    w->wTabRatio = xlsShortVal(w->wTabRatio);+}++void xlsConvertSst(SST *s)+{+    s->num=xlsIntVal(s->num);+    s->num=xlsIntVal(s->numofstr);+}++void xlsConvertXf5(XF5 *x)+{+    x->font=xlsShortVal(x->font);+    x->format=xlsShortVal(x->format);+    x->type=xlsShortVal(x->type);+    x->align=xlsShortVal(x->align);+    x->color=xlsShortVal(x->color);+    x->fill=xlsShortVal(x->fill);+    x->border=xlsShortVal(x->border);+    x->linestyle=xlsShortVal(x->linestyle);+}++void xlsConvertXf8(XF8 *x)+{+    W_ENDIAN(x->font);+    W_ENDIAN(x->format);+    W_ENDIAN(x->type);+    D_ENDIAN(x->linestyle);+    D_ENDIAN(x->linecolor);+    W_ENDIAN(x->groundcolor);+}++void xlsConvertFont(FONT *f)+{+    W_ENDIAN(f->height);+    W_ENDIAN(f->flag);+    W_ENDIAN(f->color);+    W_ENDIAN(f->bold);+    W_ENDIAN(f->escapement);+}++void xlsConvertFormat(FORMAT *f)+{+    W_ENDIAN(f->index);+}++void xlsConvertBoundsheet(BOUNDSHEET *b)+{+    D_ENDIAN(b->filepos);+}++void xlsConvertColinfo(COLINFO *c)+{+    W_ENDIAN(c->first);+    W_ENDIAN(c->last);+    W_ENDIAN(c->width);+    W_ENDIAN(c->xf);+    W_ENDIAN(c->flags);+    W_ENDIAN(c->notused);+}++void xlsConvertRow(ROW *r)+{+    W_ENDIAN(r->index);+    W_ENDIAN(r->fcell);+    W_ENDIAN(r->lcell);+    W_ENDIAN(r->height);+    W_ENDIAN(r->notused);+    W_ENDIAN(r->notused2);+    W_ENDIAN(r->flags);+    W_ENDIAN(r->xf);+}++void xlsConvertMergedcells(MERGEDCELLS *m)+{+    W_ENDIAN(m->rowf);+    W_ENDIAN(m->rowl);+    W_ENDIAN(m->colf);+    W_ENDIAN(m->coll);+}++void xlsConvertCol(COL *c)+{+    W_ENDIAN(c->row);+    W_ENDIAN(c->col);+    W_ENDIAN(c->xf);+}++void xlsConvertFormula(FORMULA *f)+{+    W_ENDIAN(f->row);+    W_ENDIAN(f->col);+    W_ENDIAN(f->xf);+	if(f->res == 0xFFFF) {+		switch(f->resid) {+		case 0:+		case 3:+			break;+		case 1:+		case 2:+			W_ENDIAN(*(WORD *)&f->resdata[1]);+			break;+		default:+			xlsConvertDouble(&f->resid);+			break;+		}+	} else {+		xlsConvertDouble(&f->resid);+	}++    W_ENDIAN(f->flags);+    W_ENDIAN(f->len);+    //fflush(stdout); left over from debugging?+}++void xlsConvertFormulaArray(FARRAY *f)+{+    W_ENDIAN(f->row1);+    W_ENDIAN(f->row2);+    W_ENDIAN(f->col1);+    W_ENDIAN(f->col2);+    W_ENDIAN(f->flags);+    W_ENDIAN(f->len);+}++void xlsConvertHeader(OLE2Header *h)+{+    int i;+    for (i=0; i<2; i++)+        h->id[i] = xlsIntVal(h->id[i]);+    for (i=0; i<4; i++)+        h->clid[i] = xlsIntVal(h->clid[i]);+    h->verminor  = xlsShortVal(h->verminor);+    h->verdll    = xlsShortVal(h->verdll);+    h->byteorder = xlsShortVal(h->byteorder);+    h->lsectorB  = xlsShortVal(h->lsectorB);+    h->lssectorB = xlsShortVal(h->lssectorB);+    h->reserved1 = xlsShortVal(h->reserved1);+    h->reserved2 = xlsIntVal(h->reserved2);+    h->reserved3 = xlsIntVal(h->reserved3);++    h->cfat      = xlsIntVal(h->cfat);+    h->dirstart  = xlsIntVal(h->dirstart);++    h->reserved4 = xlsIntVal(h->reserved4);++    h->sectorcutoff = xlsIntVal(h->sectorcutoff);+    h->sfatstart = xlsIntVal(h->sfatstart);+    h->csfat = xlsIntVal(h->csfat);+    h->difstart = xlsIntVal(h->difstart);+    h->cdif = xlsIntVal(h->cdif);+    for (i=0; i<109; i++)+        h->MSAT[i] = xlsIntVal(h->MSAT[i]);+}++void xlsConvertPss(PSS* pss)+{+    int i;+    pss->bsize = xlsShortVal(pss->bsize);+    pss->left  = xlsIntVal(pss->left);+    pss->right  = xlsIntVal(pss->right);+    pss->child  = xlsIntVal(pss->child);++    for(i=0; i<8; i++)+        pss->guid[i]=xlsShortVal(pss->guid[i]);+    pss->userflags  = xlsIntVal(pss->userflags);+/*    TIME_T	time[2]; */+    pss->sstart  = xlsIntVal(pss->sstart);+    pss->size  = xlsIntVal(pss->size);+    pss->proptype  = xlsIntVal(pss->proptype);+}++#if 0 // not used?+void xlsConvertUnicode(wchar_t *w, char *s, int len)+{+    short *x;+    int i;++    x=(short *)s;+    w = (wchar_t*)malloc((len+1)*sizeof(wchar_t));++    for(i=0; i<len; i++)+    {+        w[i]=xlsShortVal(x[i]);+    }+    w[len] = '\0';+}+#endif+
+ lib/libxls/src/ole.c view
@@ -0,0 +1,562 @@+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *+ *+ * This file is part of libxls -- A multiplatform, C/C++ library+ * for parsing Excel(TM) files.+ *+ * Redistribution and use in source and binary forms, with or without modification, are+ * permitted provided that the following conditions are met:+ *+ *    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 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.+ *+ * Copyright 2004 Komarov Valery+ * Copyright 2006 Christophe Leitienne+ * Copyright 2013 Bob Colbert+ * Copyright 2008-2013 David Hoerl+ *+ */++#include "config.h" ++#include <memory.h>+#include <math.h>+#include <string.h>+#include <stdio.h>+#include <stdlib.h>++#include <assert.h>++#include "libxls/ole.h"+#include "libxls/xlstool.h"+#include "libxls/endian.h"++extern int xls_debug;++//#define OLE_DEBUG++//static const DWORD MSATSECT		= 0xFFFFFFFC;	// -4+//static const DWORD FATSECT		= 0xFFFFFFFD;	// -3+static const DWORD ENDOFCHAIN	= 0xFFFFFFFE;	// -2+static const DWORD FREESECT		= 0xFFFFFFFF;	// -1++static size_t sector_pos(OLE2* ole2, size_t sid);+static int sector_read(OLE2* ole2, BYTE *buffer, size_t sid);+static size_t read_MSAT(OLE2* ole2, OLE2Header *oleh);++// Read next sector of stream+void ole2_bufread(OLE2Stream* olest) +{+	BYTE *ptr;++	assert(olest);+	assert(olest->ole);++    if ((DWORD)olest->fatpos!=ENDOFCHAIN)+    {+		if(olest->sfat) {+			assert(olest->ole->SSAT);+			assert(olest->buf);+			assert(olest->ole->SSecID);++			ptr = olest->ole->SSAT + olest->fatpos*olest->ole->lssector;+			memcpy(olest->buf, ptr, olest->bufsize); ++			olest->fatpos=xlsIntVal(olest->ole->SSecID[olest->fatpos]);+			olest->pos=0;+			olest->cfat++;+		} else {++			assert(olest->fatpos >= 0);++			//printf("fatpos: %d max=%u\n",olest->fatpos, (olest->ole->cfat*olest->ole->lsector)/4);+			if(olest->fatpos > (olest->ole->cfat*olest->ole->lsector)/4) exit(-1);++#if 0 // TODO: remove+			fseek(olest->ole->file,olest->fatpos*olest->ole->lsector+512,0);+			ret = fread(olest->buf,1,olest->bufsize,olest->ole->file);+			assert(ret == olest->bufsize);+#endif+			assert((int)olest->fatpos >= 0);+			sector_read(olest->ole, olest->buf, olest->fatpos);+			//printf("Fat val: %d[0x%X]\n",olest->fatpos,olest->ole->SecID[olest->fatpos], olest->ole->SecID[olest->fatpos]);+			olest->fatpos=xlsIntVal(olest->ole->SecID[olest->fatpos]);+			olest->pos=0;+			olest->cfat++;+		}+    }+	// else printf("ENDOFCHAIN!!!\n");+}++// Read part of stream+size_t ole2_read(void* buf,size_t size,size_t count,OLE2Stream* olest)+{+    size_t didReadCount=0;+    size_t totalReadCount;+	size_t needToReadCount;++	totalReadCount=size*count;++	// olest->size inited to -1+	// printf("===== ole2_read(%ld bytes)\n", totalReadCount);++    if ((long)olest->size>=0 && !olest->sfat)	// directory is -1+    {+		size_t rem;+		rem = olest->size - (olest->cfat*olest->ole->lsector+olest->pos);		+        totalReadCount = rem<totalReadCount?rem:totalReadCount;+        if (rem<=0) olest->eof=1;++		// printf("  rem=%ld olest->size=%d - subfunc=%d\n", rem, olest->size, (olest->cfat*olest->ole->lsector+olest->pos) );+		//printf("  totalReadCount=%d (rem=%d size*count=%ld)\n", totalReadCount, rem, size*count);+	}++	while ((!olest->eof) && (didReadCount!=totalReadCount))+	{+		unsigned long remainingBytes;++		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);+			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;+			ole2_bufread(olest);+		}+		assert(didReadCount <= totalReadCount);+		//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))+		{+			olest->eof=1;+		}++		//printf("  eof=%d (didReadCount=%ld != totalReadCount=%ld)\n", olest->eof, didReadCount, totalReadCount);+	}+	// printf("  didReadCount=%ld EOF=%d\n", didReadCount, olest->eof);+	// printf("=====\n");++#ifdef OLE_DEBUG+    printf("----------------------------------------------\n");+    printf("ole2_read (end)\n");+    printf("start:		%li \n",olest->start);+    printf("pos:		%li \n",olest->pos);+    printf("cfat:		%d \n",olest->cfat);+    printf("size:		%d \n",olest->size);+    printf("fatpos:		%li \n",olest->fatpos);+    printf("bufsize:		%li \n",olest->bufsize);+    printf("eof:		%d \n",olest->eof);+#endif++    return(didReadCount);+}++// Open stream in logical ole file+OLE2Stream* ole2_sopen(OLE2* ole,DWORD start, size_t size)+{+    OLE2Stream* olest=NULL;++#ifdef OLE_DEBUG+    printf("----------------------------------------------\n");+    printf("ole2_sopen start=%lXh\n", start);+#endif++	olest=(OLE2Stream*)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;+		olest->sfat = 1;+	} else {+		olest->bufsize=ole->lsector;+	}+	olest->buf=malloc(olest->bufsize);+	ole2_bufread(olest);++	// if(xls_debug) printf("sopen: sector=%d next=%d\n", start, olest->fatpos);+    return olest;+}++// Move in stream+void ole2_seek(OLE2Stream* olest,DWORD ofs)+{+	if(olest->sfat) {+		ldiv_t div_rez=ldiv(ofs,olest->ole->lssector);+		int i;+		olest->fatpos=olest->start;++		if (div_rez.quot!=0)+		{+			for (i=0;i<div_rez.quot;i++)+				olest->fatpos=xlsIntVal(olest->ole->SSecID[olest->fatpos]);+		}++		ole2_bufread(olest);+		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);+		int i;+		olest->fatpos=olest->start;++		if (div_rez.quot!=0)+		{+			for (i=0;i<div_rez.quot;i++)+				olest->fatpos=xlsIntVal(olest->ole->SecID[olest->fatpos]);+		}++		ole2_bufread(olest);+		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);+	}+}++// Open logical file contained in physical OLE file+OLE2Stream*  ole2_fopen(OLE2* ole,BYTE* file)+{+    OLE2Stream* olest;+    int i;++#ifdef OLE_DEBUG+    printf("----------------------------------------------\n");+    printf("ole2_fopen %s\n", file);+#endif++    for (i=0;i<ole->files.count;i++) {+		BYTE *str = ole->files.file[i].name;+#ifdef OLE_DEBUG+		printf("----------------------------------------------\n");+		printf("ole2_fopen found %s\n", str);+#endif+        if (str && strcmp((char *)str,(char *)file)==0)	// newer versions of Excel don't write the "Root Entry" string for the first set of data+        {+            olest=ole2_sopen(ole,ole->files.file[i].start,ole->files.file[i].size);+            return(olest);+        }+	}+    return(NULL);+}++// Open physical file+OLE2* ole2_open(const BYTE *file)+{+    //BYTE buf[1024];+    OLE2Header* oleh;+    OLE2* ole;+    OLE2Stream* olest;+    PSS*	pss;+    BYTE* name = NULL;++#ifdef OLE_DEBUG+    printf("----------------------------------------------\n");+    printf("ole2_open %s\n", file);+#endif++	if(xls_debug) printf("ole2_open: %s\n", file);+    ole=(OLE2*)calloc(1, sizeof(OLE2));+    if (!(ole->file=fopen((char *)file,"rb")))+    {+        if(xls_debug) printf("File not found\n");+        free(ole);+        return(NULL);+    }+    // read header and check magic numbers+    oleh=(OLE2Header*)malloc(512);+    fread(oleh,1,512,ole->file);+    xlsConvertHeader(oleh);++	// make sure the file looks good. Note: this code only works on Little Endian machines+	if(oleh->id[0] != 0xE011CFD0 || oleh->id[1] != 0xE11AB1A1 || oleh->byteorder != 0xFFFE) {+		fclose(ole->file);+        printf("Not an excel file\n");+		free(ole);+		return NULL;+	}++    //ole->lsector=(WORD)pow(2,oleh->lsector);+    //ole->lssector=(WORD)pow(2,oleh->lssector);+	ole->lsector=512;+    ole->lssector=64;+	assert(oleh->lsectorB==9);	// 2**9 == 512+	assert(oleh->lssectorB==6);	// 2**6 == 64+	+    ole->cfat=oleh->cfat;+    ole->dirstart=oleh->dirstart;+    ole->sectorcutoff=oleh->sectorcutoff;+    ole->sfatstart=oleh->sfatstart;+    ole->csfat=oleh->csfat;+    ole->difstart=oleh->difstart;+    ole->cdif=oleh->cdif;+    ole->files.count=0;++#ifdef OLE_DEBUG+		printf("==== OLE HEADER ====\n");+		//printf ("Header Size:   %i \n", sizeof(OLE2Header));+		//printf ("id[0]-id[1]:   %X-%X \n", oleh->id[0], oleh->id[1]);+		printf ("verminor:      %X \n",oleh->verminor);+		printf ("verdll:        %X \n",oleh->verdll);+		//printf ("Byte order:    %X \n",oleh->byteorder);+		printf ("sect len:      %X (%i)\n",ole->lsector,ole->lsector);		// ole+		printf ("mini len:      %X (%i)\n",ole->lssector,ole->lssector);	// ole+		printf ("Fat sect.:     %i \n",oleh->cfat);+		printf ("Dir Start:     %i \n",oleh->dirstart);+		+		printf ("Mini Cutoff:   %i \n",oleh->sectorcutoff);+		printf ("MiniFat Start: %X \n",oleh->sfatstart);+		printf ("Count MFat:    %i \n",oleh->csfat);+		printf ("Dif start:     %X \n",oleh->difstart);+		printf ("Count Dif:     %i \n",oleh->cdif);+		printf ("Fat Size:      %u (0x%X) \n",oleh->cfat*ole->lsector,oleh->cfat*ole->lsector);+#endif+    // read directory entries+    read_MSAT(ole, oleh);++	// reuse this buffer+    pss = (PSS*)oleh;+	// oleh = (void *)NULL; // Not needed as oleh not used from here on+	+    olest=ole2_sopen(ole,ole->dirstart, -1);+    do+    {+        ole2_read(pss,1,sizeof(PSS),olest);+        xlsConvertPss(pss);+        name=unicode_decode(pss->name, pss->bsize, 0, "UTF-8");+#ifdef OLE_DEBUG	+		printf("OLE NAME: %s count=%d\n", name, ole->files.count);+#endif+        if (pss->type == PS_USER_ROOT || pss->type == PS_USER_STREAM) // (name!=NULL) // +        {++#ifdef OLE_DEBUG		+			printf("OLE TYPE: %s file=%d \n", pss->type == PS_USER_ROOT ? "root" : "user", ole->files.count);+#endif		+            if (ole->files.count==0)+            {+                ole->files.file=malloc(sizeof(struct st_olefiles_data));+            } else {+                ole->files.file=realloc(ole->files.file,(ole->files.count+1)*sizeof(struct st_olefiles_data));+            }+            ole->files.file[ole->files.count].name=name;+            ole->files.file[ole->files.count].start=pss->sstart;+            ole->files.file[ole->files.count].size=pss->size;+            ole->files.count++;+			+			if(pss->sstart == ENDOFCHAIN) {+				if (xls_debug) verbose("END OF CHAIN\n");+			} else+			if(pss->type == PS_USER_STREAM) {+#ifdef OLE_DEBUG+					printf("----------------------------------------------\n");+					printf("name: %s (size=%d [c=%c])\n", name, pss->bsize, name ? name[0]:' ');+					printf("bsize %i\n",pss->bsize);+					printf("type %i\n",pss->type);+					printf("flag %i\n",pss->flag);+					printf("left %X\n",pss->left);+					printf("right %X\n",pss->right);+					printf("child %X\n",pss->child);+					printf("guid %.4X-%.4X-%.4X-%.4X %.4X-%.4X-%.4X-%.4X\n",pss->guid[0],pss->guid[1],pss->guid[2],pss->guid[3],+						pss->guid[4],pss->guid[5],pss->guid[6],pss->guid[7]);+					printf("user flag %.4X\n",pss->userflags);+					printf("sstart %.4d\n",pss->sstart);+					printf("size %.4d\n",pss->size);+#endif+			} else+			if(pss->type == PS_USER_ROOT) {+				DWORD sector, k, blocks;+				BYTE *wptr;+				+				blocks = (pss->size + (ole->lsector - 1)) / ole->lsector;	// count partial+				ole->SSAT = (BYTE *)malloc(blocks*ole->lsector);+				// printf("blocks %d\n", blocks);++				assert(ole->SSecID);+				+				sector = pss->sstart;+				wptr=(BYTE*)ole->SSAT;+				for(k=0; k<blocks; ++k) {+					// printf("block %d sector %d\n", k, sector);+					assert(sector != ENDOFCHAIN);+					fseek(ole->file,sector*ole->lsector+512,0);+					fread(wptr,1,ole->lsector,ole->file);+					wptr += ole->lsector;+					sector = xlsIntVal(ole->SecID[sector]);+				}+			}	+		} else {+			free(name);+		}+    }+    while (!olest->eof);++	ole2_fclose(olest);+    free(pss);++    return ole;+}++void ole2_close(OLE2* ole2)+{+    int i;+	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);+}++void ole2_fclose(OLE2Stream* ole2st)+{+	free(ole2st->buf);+	free(ole2st);+}++// Return offset in bytes of a sector from its sid+static size_t sector_pos(OLE2* ole2, size_t sid)+{+    return 512 + sid * ole2->lsector;+}+// Read one sector from its sid+static int sector_read(OLE2* ole2, BYTE *buffer, size_t 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 = fseek(ole2->file, sector_pos(ole2, sid), SEEK_SET);+	if(seeked != 0) {+		printf("seek: wanted to seek to sector %zu (0x%zx) loc=%zu\n", sid, sid, sector_pos(ole2, sid));+	}+	assert(seeked == 0);+	+	num = fread(buffer, ole2->lsector, 1, ole2->file);+	if(num != 1) {+		fprintf(stderr, "fread: wanted 1 got %zu loc=%zu\n", num, sector_pos(ole2, sid));+	}+	assert(num == 1);++    return 0;+}++// Read MSAT+static size_t read_MSAT(OLE2* ole2, OLE2Header* oleh)+{+    int sectorNum;++    // reconstitution of the MSAT+    ole2->SecID=malloc(ole2->cfat*ole2->lsector);++    // read first 109 sectors of MSAT from header+    {+        int count;+        count = (ole2->cfat < 109) ? ole2->cfat : 109;+        for (sectorNum = 0; sectorNum < count; sectorNum++)+        {+			assert(sectorNum >= 0);+            sector_read(ole2, (BYTE*)(ole2->SecID)+sectorNum*ole2->lsector, oleh->MSAT[sectorNum]);+        }+    }++    // Add additionnal sectors of the MSAT+    {+        DWORD sid = ole2->difstart;++		BYTE *sector = 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+           sector_read(ole2, sector, sid);++           // read content+           for (posInSector = 0; posInSector < (ole2->lsector-4)/4; posInSector++)+		   {+              DWORD s = *(DWORD_UA *)(sector + posInSector*4);+              //printf("   s[%d]=%d (0x%x)\n", posInSector, s, s);++              if (s != FREESECT)+                {+                 sector_read(ole2, (BYTE*)(ole2->SecID)+sectorNum*ole2->lsector, s);+                 sectorNum++;+                }+			}+			sid = *(DWORD_UA *)(sector + posInSector*4);+			//printf("   s[%d]=%d (0x%x)\n", posInSector, sid, sid);+		}+		free(sector);+    }+#ifdef OLE_DEBUG+	if(xls_debug) {+		//printf("==== READ IN SECTORS FOR MSAT TABLE====\n");+		int i;+		for(i=0; i<512/4; ++i) {	// just the first block+			if(ole2->SecID[i] != FREESECT) printf("SecID[%d]=%d\n", i, ole2->SecID[i]);+		}+	}+	//exit(0);+#endif++	// read in short table+	if(ole2->sfatstart != ENDOFCHAIN) {+		DWORD sector, k;+		BYTE *wptr;+		+		ole2->SSecID = (DWORD *)malloc(ole2->csfat*ole2->lsector);+		sector = ole2->sfatstart;+		wptr=(BYTE*)ole2->SSecID;+		for(k=0; k<ole2->csfat; ++k) {+			assert(sector != ENDOFCHAIN);+			fseek(ole2->file,sector*ole2->lsector+512,0);+			fread(wptr,1,ole2->lsector,ole2->file);+			wptr += ole2->lsector;+			sector = ole2->SecID[sector];+		}+#ifdef OLE_DEBUG+		if(xls_debug) {+			int i;+			for(i=0; i<512/4; ++i) {+				if(ole2->SSecID[i] != FREESECT) printf("SSecID[%d]=%d\n", i, ole2->SSecID[i]);+			}+		}+#endif+	}++    return 0;+}++
+ lib/libxls/src/xls.c view
@@ -0,0 +1,2184 @@+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *+ *+ * This file is part of libxls -- A multiplatform, C/C++ library+ * for parsing Excel(TM) files.+ *+ * Redistribution and use in source and binary forms, with or without modification, are+ * permitted provided that the following conditions are met:+ *+ *    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 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.+ *+ * Copyright 2004 Komarov Valery+ * Copyright 2006 Christophe Leitienne+ * Copyright 2013 Bob Colbert+ * Copyright 2008-2013 David Hoerl+ *+ */++#include "config.h"++#include <stdio.h>+#include <stdlib.h>+#include <errno.h>++#include <memory.h>+#include <math.h>+#include <sys/types.h>+#include <string.h>+#include <wchar.h>+#include <assert.h>++#include "libxls/endian.h"+#include "libxls/xls.h"++#ifndef min+#define min(a,b) ((a) < (b) ? (a) : (b))+#endif++/* #define DEBUG_DRAWINGS */+int xls_debug = 0;++static double NumFromRk(DWORD_UA drk);+static xls_formula_handler formula_handler;++extern void xls_addSST(xlsWorkBook* pWB,SST* sst,DWORD size);+extern void xls_appendSST(xlsWorkBook* pWB,BYTE* buf,DWORD size);+extern void xls_addFormat(xlsWorkBook* pWB,FORMAT* format);+extern BYTE* xls_addSheet(xlsWorkBook* pWB,BOUNDSHEET* bs);+extern void xls_addRow(xlsWorkSheet* pWS,ROW* row);+extern void xls_makeTable(xlsWorkSheet* pWS);+extern struct st_cell_data *xls_addCell(xlsWorkSheet* pWS,BOF* bof,BYTE* buf);+extern BYTE *xls_addFont(xlsWorkBook* pWB,FONT* font);+extern void xls_addXF8(xlsWorkBook* pWB,XF8* xf);+extern void xls_addXF5(xlsWorkBook* pWB,XF5* xf);+extern void xls_addColinfo(xlsWorkSheet* pWS,COLINFO* colinfo);+extern void xls_mergedCells(xlsWorkSheet* pWS,BOF* bof,BYTE* buf);+extern void xls_parseWorkBook(xlsWorkBook* pWB);+extern void xls_preparseWorkSheet(xlsWorkSheet* pWS);+extern void xls_formatColumn(xlsWorkSheet* pWS);+extern void xls_parseWorkSheet(xlsWorkSheet* pWS);+extern void xls_dumpSummary(char *buf,int isSummary,xlsSummaryInfo	*pSI);++#ifdef AIX+#pragma pack(1)+#else+#pragma pack(push, 1)+#endif++typedef struct {+	uint32_t		format[4];+	uint32_t		offset;+} sectionList;++typedef struct {+	uint16_t		sig;+	uint16_t		_empty;+	uint32_t		os;+	uint32_t		format[4];+	uint32_t		count;+	sectionList		secList[0];+} header;++typedef struct {+	uint32_t		propertyID;+	uint32_t		sectionOffset;+} propertyList;++typedef struct {+	uint32_t		length;+	uint32_t		numProperties;+	propertyList	properties[0];+} sectionHeader;++typedef struct {+	uint32_t		propertyID;+	uint32_t		data[0];+} 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)+{+	xls_debug = debug;+    return 1;+}++void xls_addSST(xlsWorkBook* pWB,SST* sst,DWORD size)+{+    verbose("xls_addSST");++    pWB->sst.continued=0;+    pWB->sst.lastln=0;+    pWB->sst.lastid=0;+    pWB->sst.lastrt=0;+    pWB->sst.lastsz=0;++    pWB->sst.count = sst->num;+    pWB->sst.string =(struct str_sst_string *)calloc(pWB->sst.count, sizeof(struct str_sst_string));+    xls_appendSST(pWB,&sst->strings,size-8);+}++void xls_appendSST(xlsWorkBook* pWB,BYTE* buf,DWORD size)+{+    DWORD ln;	// String character count+    DWORD ofs;	// Current offset in SST buffer+    DWORD rt;	// Count of rich text formatting runs+    DWORD sz;	// Size of asian phonetic settings block+    BYTE flag;	// String flags+    BYTE* ret;++    if (xls_debug) {+	    printf("xls_appendSST %u\n", size);+    }++	sz = rt = ln = 0;	// kch+    ofs=0;++	while(ofs<size)+    {+        int ln_toread;++        // Restore state when we're in a continue record+        // or read string length+        if (pWB->sst.continued)+        {+            ln=pWB->sst.lastln;+            rt=pWB->sst.lastrt;+            sz=pWB->sst.lastsz;+        }+        else+        {+            ln=xlsShortVal(*(WORD_UA *)(buf+ofs));+            rt = 0;+            sz = 0;++            ofs+=2;+        }++		if (xls_debug) {+        	printf("ln=%u\n", ln);+		}++        // Read flags+        if ( (!pWB->sst.continued) || ( (pWB->sst.continued) && (ln != 0) ) )+        {+            flag=*(BYTE *)(buf+ofs);+            ofs++;++            // Count of rich text formatting runs+            if (flag & 0x8)+            {+                rt=xlsShortVal(*(WORD_UA *)(buf+ofs));+                ofs+=2;+            }++            // Size of asian phonetic settings block+            if (flag & 0x4)+            {+                sz=xlsIntVal(*(DWORD_UA *)(buf+ofs));+                ofs+=4;++				if (xls_debug) {+					printf("sz=%u\n", sz);+				}+            }+        }+        else+        {+            flag = 0;+        }++		// Read characters (compressed or not)+        ln_toread = 0;+        if (ln > 0)+        {+            if (flag & 0x1)+            {+                size_t new_len = 0;+                ln_toread = min((size-ofs)/2, ln);+                ret=unicode_decode(buf+ofs,ln_toread*2,&new_len,pWB->charset);++                if (ret == NULL)+                {+                    ret = (BYTE *)strdup("*failed to decode utf16*");+                    new_len = strlen((char *)ret);+                }++                ret = (BYTE *)realloc(ret,new_len+1);+                *(BYTE*)(ret+new_len)=0;++                ln -= ln_toread;+                ofs+=ln_toread*2;++                if (xls_debug) {+	                printf("String16SST: %s(%zd)\n",ret,new_len);+                }+            }+            else+            {+                ln_toread = min((size-ofs), ln);++				ret = utf8_decode((buf+ofs), ln_toread, pWB->charset);++                ln  -= ln_toread;+                ofs +=ln_toread;++                if (xls_debug) {+                	printf("String8SST: %s(%u) \n",ret,ln);+                }+            }+        }+        else+        {+         ret = (BYTE *)strdup("");+        }++        if (  (ln_toread > 0)+            ||(!pWB->sst.continued) )+        {+            // Concat string if it's a continue, or add string in table+            if (!pWB->sst.continued)+            {+                pWB->sst.lastid++;+                pWB->sst.string[pWB->sst.lastid-1].str=ret;+            }+            else+            {+                BYTE *tmp;+                tmp=pWB->sst.string[pWB->sst.lastid-1].str;+                tmp=(BYTE *)realloc(tmp,strlen((char *)tmp)+strlen((char *)ret)+1);+                pWB->sst.string[pWB->sst.lastid-1].str=tmp;+                memcpy(tmp+strlen((char *)tmp),ret,strlen((char *)ret)+1);+				free(ret);+            }++			if (xls_debug) {+	            printf("String %4u: %s<end>\n", pWB->sst.lastid-1, pWB->sst.string[pWB->sst.lastid-1].str);+			}+        }++		// Jump list of rich text formatting runs+        if (  (ofs < size)+            &&(rt > 0) )+          {+           int rt_toread = min((size-ofs)/4, rt);+           rt -= rt_toread;+           ofs += rt_toread*4;+          }++		// Jump asian phonetic settings block+        if (  (ofs < size)+            &&(sz > 0) )+          {+           int sz_toread = min((size-ofs), sz);+           sz -= sz_toread;+           ofs += sz_toread;+          }++        pWB->sst.continued=0;+    }++    // Save current character count and count of rich text formatting runs and size of asian phonetic settings block+	if (ln > 0 || rt > 0 || sz > 0) {+		pWB->sst.continued = 1;+		pWB->sst.lastln = ln;+		pWB->sst.lastrt = rt;+		pWB->sst.lastsz = sz;++		if (xls_debug) {+			printf("continued: ln=%u, rt=%u, sz=%u\n", ln, rt, sz);+		}+	}+}++static double NumFromRk(DWORD_UA drk)+{+	double ret;++	// What kind of value is this ?+    if (drk & 0x02) {+    	// Integer value+		int tmp = (int)drk >> 2;	// cast to keep it negative in < 0+        ret = (double)tmp;+    } else {+    	// Floating point value;+		unsigned64_t tmp = drk & 0xfffffffc;+		tmp <<= 32;+		memcpy(&ret, &tmp, sizeof(unsigned64_t));+    }+    // Is value multiplied by 100 ?+    if (drk & 0x01) {+        ret /= 100.0;+    }+    return ret;+}++BYTE* xls_addSheet(xlsWorkBook* pWB, BOUNDSHEET *bs)+{+	BYTE* name;+	DWORD filepos;+	BYTE visible, type;++	filepos = bs->filepos;+	visible = bs->visible;+	type = bs->type;++	// 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, 0, pWB->is5ver, pWB->charset);+	// printf("name=%s\n", name);++	if(xls_debug) {+		printf ("xls_addSheet[0x%x]\n", type);+		switch (type & 0x0f)+		{+		case 0x00:+			/* worksheet or dialog sheet */+			printf ("85: Worksheet or dialog sheet\n");+			break;+		case 0x01:+			/* Microsoft Excel 4.0 macro sheet */+			printf ("85: Microsoft Excel 4.0 macro sheet\n");+			break;+		case 0x02:+			/* Chart */+			printf ("85: Chart sheet\n");+			break;+		case 0x06:+			/* Visual Basic module */+			printf ("85: Visual Basic sheet\n");+			break;+		default:+			printf ("???\n");+			break;+		}+		printf("visible: %x\n", visible);+		printf("    Pos: %Xh\n",filepos);+		printf("   type: %.4Xh\n",type);+		printf("   name: %s\n", name);+	}++    if (pWB->sheets.count==0)+    {+        pWB->sheets.sheet=(struct st_sheet_data *) malloc(sizeof (struct st_sheet_data));+    }+    else+    {+        pWB->sheets.sheet=(struct st_sheet_data *) realloc(pWB->sheets.sheet,(pWB->sheets.count+1)*sizeof (struct st_sheet_data));+    }+    pWB->sheets.sheet[pWB->sheets.count].name=name;+    pWB->sheets.sheet[pWB->sheets.count].filepos=filepos;+    pWB->sheets.sheet[pWB->sheets.count].visibility=visible;+    pWB->sheets.sheet[pWB->sheets.count].type=type;+    pWB->sheets.count++;++	return name;+}+++void xls_addRow(xlsWorkSheet* pWS,ROW* row)+{+    struct st_row_data* tmp;++    //verbose ("xls_addRow");++    tmp=&pWS->rows.row[row->index];+    tmp->height=row->height;+    tmp->fcell=row->fcell;+    tmp->lcell=row->lcell;+    tmp->flags=row->flags;+    tmp->xf=row->xf&0xfff;+    tmp->xfflags=(row->xf >> 8)&0xf0;+    if(xls_debug) xls_showROW(tmp);+}++void xls_makeTable(xlsWorkSheet* pWS)+{+    DWORD i,t;+    struct st_row_data* tmp;+    verbose ("xls_makeTable");++    pWS->rows.row=(struct st_row_data *)calloc((pWS->rows.lastrow+1),sizeof(struct st_row_data));++	// printf("ALLOC: rows=%d cols=%d\n", pWS->rows.lastrow, pWS->rows.lastcol);+    for (t=0;t<=pWS->rows.lastrow;t++)+    {+        tmp=&pWS->rows.row[t];+        tmp->index=t;+        tmp->fcell=0;+        tmp->lcell=pWS->rows.lastcol;++		tmp->cells.count = pWS->rows.lastcol+1;+        tmp->cells.cell=(struct st_cell_data *)calloc(tmp->cells.count,sizeof(struct st_cell_data));++        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;+        }+    }+}++struct st_cell_data *xls_addCell(xlsWorkSheet* pWS,BOF* bof,BYTE* buf)+{+    struct st_cell_data*	cell;+    struct st_row_data*		row;+    int						i;++	verbose ("xls_addCell");++	// 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)];+    cell->id=bof->id;+    cell->xf=xlsShortVal(((COL*)buf)->xf);++    switch (bof->id)+    {+    case XLS_RECORD_FORMULA:+    case XLS_RECORD_FORMULA_ALT:+		// test for formula, if+		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);+		} else {+			cell->l = 0xFFFF;+			double d = ((FORMULA*)buf)->resdata[1];+			switch(((FORMULA*)buf)->resid) {+			case 0:		// String+				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");+				break;+			case 2:		// error+				memcpy(&cell->d, &d, sizeof(double)); // Required for ARM+				sprintf((char *)(cell->str = malloc(sizeof("error"))), "error");+				break;+			case 3:		// empty string+				cell->str = calloc(1,1);+				break;+			}+		}+		if(formula_handler) formula_handler(bof->id, bof->size, buf);+        break;+    case XLS_RECORD_MULRK:+printf("MULRK: %d\n", bof->size);+        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) );+            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);+        }+        break;+    case XLS_RECORD_MULBLANK:+        for (i = 0; i < (bof->size - 6)/2; i++)	// 6 == 2 row + 2 col + 2 trailing index+        {+            cell=&row->cells.cell[xlsShortVal(((MULBLANK*)buf)->col) + i];+            cell->id=XLS_RECORD_BLANK;+            cell->xf=xlsShortVal(((MULBLANK*)buf)->xf[i]);+            cell->str=xls_getfcell(pWS->workbook,cell, NULL);+        }+        break;+    case XLS_RECORD_LABELSST:+    case XLS_RECORD_LABEL:+		cell->str=xls_getfcell(pWS->workbook,cell,(WORD_UA *)&((LABEL*)buf)->value);+		sscanf((char *)cell->str, "%d", &cell->l);+		sscanf((char *)cell->str, "%lf", &cell->d);+		break;+    case XLS_RECORD_RK:+        cell->d=NumFromRk(xlsIntVal(((RK*)buf)->value));+        cell->str=xls_getfcell(pWS->workbook,cell, NULL);+        break;+    case XLS_RECORD_BLANK:+        break;+    case XLS_RECORD_NUMBER:+        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);+        break;+    case XLS_RECORD_BOOLERR:+        cell->d = ((BOOLERR *)buf)->value;+        if (((BOOLERR *)buf)->iserror) {+            sprintf((char *)(cell->str = malloc(sizeof("error"))), "error");+        } else {+            sprintf((char *)(cell->str = malloc(sizeof("bool"))), "bool");+        }+        break;+    default:+        cell->str=xls_getfcell(pWS->workbook,cell, NULL);+        break;+    }+    if (xls_debug) xls_showCell(cell);++	return cell;+}++BYTE *xls_addFont(xlsWorkBook* pWB, FONT* font)+{+    struct st_font_data* tmp;++    verbose("xls_addFont");+    if (pWB->fonts.count==0)+    {+        pWB->fonts.font=(struct st_font_data *) malloc(sizeof(struct st_font_data));+    } else {+        pWB->fonts.font=(struct st_font_data *) realloc(pWB->fonts.font,(pWB->fonts.count+1)*sizeof(struct st_font_data));+    }++    tmp=&pWB->fonts.font[pWB->fonts.count];++    tmp->name=get_string((BYTE*)&font->name, 0, pWB->is5ver, pWB->charset);++    tmp->height=font->height;+    tmp->flag=font->flag;+    tmp->color=font->color;+    tmp->bold=font->bold;+    tmp->escapement=font->escapement;+    tmp->underline=font->underline;+    tmp->family=font->family;+    tmp->charset=font->charset;++    //	xls_showFont(tmp);+    pWB->fonts.count++;++	return tmp->name;+}++void xls_addFormat(xlsWorkBook* pWB, FORMAT* format)+{+    struct st_format_data* tmp;++    verbose("xls_addFormat");+    if (pWB->formats.count==0)+    {+        pWB->formats.format=(struct st_format_data *) malloc(sizeof(struct st_format_data));+    } else {+        pWB->formats.format=(struct st_format_data *) realloc(pWB->formats.format,(pWB->formats.count+1)*sizeof(struct st_format_data));+    }++    tmp=&pWB->formats.format[pWB->formats.count];+    tmp->index=format->index;+    tmp->value=get_string(format->value, (BYTE)!pWB->is5ver, (BYTE)pWB->is5ver, pWB->charset);+    if(xls_debug) xls_showFormat(tmp);+    pWB->formats.count++;+}++void xls_addXF8(xlsWorkBook* pWB,XF8* xf)+{+    struct st_xf_data* tmp;++    verbose("xls_addXF");+    if (pWB->xfs.count==0)+    {+        pWB->xfs.xf=(struct st_xf_data *) malloc(sizeof(struct st_xf_data));+    }+    else+    {+        pWB->xfs.xf=(struct st_xf_data *) realloc(pWB->xfs.xf,(pWB->xfs.count+1)*sizeof(struct st_xf_data));+    }++    tmp=&pWB->xfs.xf[pWB->xfs.count];++    tmp->font=xf->font;+    tmp->format=xf->format;+    tmp->type=xf->type;+    tmp->align=xf->align;+    tmp->rotation=xf->rotation;+    tmp->ident=xf->ident;+    tmp->usedattr=xf->usedattr;+    tmp->linestyle=xf->linestyle;+    tmp->linecolor=xf->linecolor;+    tmp->groundcolor=xf->groundcolor;++    //	xls_showXF(tmp);+    pWB->xfs.count++;+}+void xls_addXF5(xlsWorkBook* pWB,XF5* xf)+{+    struct st_xf_data* tmp;++    verbose("xls_addXF");+    if (pWB->xfs.count==0)+    {+        pWB->xfs.xf=(struct st_xf_data *) malloc(sizeof(struct st_xf_data));+    }+    else+    {+        pWB->xfs.xf=(struct st_xf_data *) realloc(pWB->xfs.xf,(pWB->xfs.count+1)*sizeof(struct st_xf_data));+    }++    tmp=&pWB->xfs.xf[pWB->xfs.count];++    tmp->font=xf->font;+    tmp->format=xf->format;+    tmp->type=xf->type;+    tmp->align=(BYTE)xf->align;+/*+    tmp->rotation=xf->rotation;+    tmp->ident=xf->ident;+    tmp->usedattr=xf->usedattr;+    tmp->linestyle=xf->linestyle;+    tmp->linecolor=xf->linecolor;+    tmp->groundcolor=xf->groundcolor;+*/++    //	xls_showXF(tmp);+    pWB->xfs.count++;+}++void xls_addColinfo(xlsWorkSheet* pWS,COLINFO* colinfo)+{+    struct st_colinfo_data* tmp;++    verbose("xls_addColinfo");+    if (pWS->colinfo.count==0)+    {+        pWS->colinfo.col=(struct st_colinfo_data *) malloc(sizeof(struct st_colinfo_data));+    }+    else+    {+        pWS->colinfo.col=(struct st_colinfo_data *) realloc(pWS->colinfo.col,(pWS->colinfo.count+1)*sizeof(struct st_colinfo_data));+    }++    tmp=&pWS->colinfo.col[pWS->colinfo.count];+    tmp->first=colinfo->first;+    tmp->last=colinfo->last;+    tmp->width=colinfo->width;+    tmp->xf=colinfo->xf;+    tmp->flags=colinfo->flags;++    if(xls_debug) xls_showColinfo(tmp);+    pWS->colinfo.count++;+}++void xls_mergedCells(xlsWorkSheet* pWS,BOF* bof,BYTE* buf)+{+    int count=xlsShortVal(*((WORD_UA *)buf));+    int i,c,r;+    struct MERGEDCELLS* span;+    verbose("Merged Cells");+    for (i=0;i<count;i++)+    {+        span=(struct MERGEDCELLS*)(buf+(2+i*sizeof(struct MERGEDCELLS)));+        xlsConvertMergedcells(span);+        //		printf("Merged Cells: [%i,%i] [%i,%i] \n",span->colf,span->rowf,span->coll,span->rowl);+        for (r=span->rowf;r<=span->rowl;r++)+            for (c=span->colf;c<=span->coll;c++)+                pWS->rows.row[r].cells.cell[c].isHidden=1;+        pWS->rows.row[span->rowf].cells.cell[span->colf].colspan=(span->coll-span->colf+1);+        pWS->rows.row[span->rowf].cells.cell[span->colf].rowspan=(span->rowl-span->rowf+1);+        pWS->rows.row[span->rowf].cells.cell[span->colf].isHidden=0;+    }+}++void xls_parseWorkBook(xlsWorkBook* pWB)+{+    BOF bof1;+    BOF bof2;+    BYTE* buf;+	BYTE once;++	// this to prevent compiler warnings+	once=0;+	bof2.size = 0;+	bof2.id = 0;+    verbose ("xls_parseWorkBook");+    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); +		}++        ole2_read(&bof1, 1, 4, pWB->olestr);+        xlsConvertBof(&bof1);+ 		if(xls_debug) xls_showBOF(&bof1);++        buf=(BYTE *)malloc(bof1.size);+        ole2_read(buf, 1, bof1.size, pWB->olestr);++        switch (bof1.id) {+        case XLS_RECORD_EOF:+            //verbose("EOF");+            break;+        case XLS_RECORD_BOF:	// BIFF5-8+			{+				BIFF *b = (BIFF*)buf;+                xlsConvertBiff(b);+				if (b->ver==0x600)+					pWB->is5ver=0;+				else+					pWB->is5ver=1;+				pWB->type=b->type;++				if(xls_debug) {+					printf("version: %s\n", pWB->is5ver ? "BIFF5" : "BIFF8" );+					printf("   type: %.2X\n", pWB->type);+				}+			}+            break;++        case XLS_RECORD_CODEPAGE:+            pWB->codepage=xlsShortVal(*(WORD_UA *)buf);+			if(xls_debug) printf("codepage=%x\n", pWB->codepage);+            break;++        case XLS_RECORD_CONTINUE:+			if(once) {+				if (bof2.id==XLS_RECORD_SST)+					xls_appendSST(pWB,buf,bof1.size);+				bof1=bof2;+			}+            break;++		case XLS_RECORD_WINDOW1:+			{+				WIND1 *w = (WIND1*)buf;+                xlsConvertWindow(w);+				pWB->activeSheetIdx = w->itabCur;+				if(xls_debug) {+					printf("WINDOW1: ");+					printf("xWn    : %d\n", w->xWn/20);+					printf("yWn    : %d\n", w->yWn/20);+					printf("dxWn   : %d\n", w->dxWn/20);+					printf("dyWn   : %d\n", w->dyWn/20);+					printf("grbit  : %d\n", w->grbit);+					printf("itabCur: %d\n", w->itabCur);+					printf("itabFi : %d\n", w->itabFirst);+					printf("ctabSel: %d\n", w->ctabSel);+					printf("wTabRat: %d\n", w->wTabRatio);+				}+			}+			break;++        case XLS_RECORD_SST:+			//printf("ADD SST\n");+			//if(xls_debug) dumpbuf((BYTE *)"/tmp/SST",bof1.size,buf);+            xlsConvertSst((SST *)buf);+            xls_addSST(pWB,(SST*)buf,bof1.size);+            break;++        case XLS_RECORD_EXTSST:+            //if(xls_debug > 1000) dumpbuf((BYTE *)"/tmp/EXTSST",bof1.size,buf);+            break;++        case XLS_RECORD_BOUNDSHEET:+			{+				//printf("ADD SHEET\n");+				BOUNDSHEET *bs = (BOUNDSHEET *)buf;+                xlsConvertBoundsheet(bs);+				//char *s;+				// different for BIFF5 and BIFF8+				/*s = */ xls_addSheet(pWB,bs);+			}+            break;++        case XLS_RECORD_XF:+			if(pWB->is5ver) {+				XF5 *xf;+				xf = (XF5 *)buf;+                xlsConvertXf5(xf);++				xls_addXF5(pWB,xf);+				if(xls_debug) {+					printf("   font: %d\n", xf->font);+					printf(" format: %d\n", xf->format);+					printf("   type: %.4x\n", xf->type);+					printf("  align: %.4x\n", xf->align);+					printf("rotatio: %.4x\n", xf->color);+					printf("  ident: %.4x\n", xf->fill);+					printf("usedatt: %.4x\n", xf->border);+					printf("linesty: %.4x\n", xf->linestyle);+				}+			} else {+				XF8 *xf;+				xf = (XF8 *)buf;+                xlsConvertXf8(xf);++				xls_addXF8(pWB,xf);+				if(xls_debug) {+					xls_showXF(xf);+				}+			}+            break;++        case XLS_RECORD_FONT:+        case XLS_RECORD_FONT_ALT:+			{+				BYTE *s;+				FONT *f = (FONT*)buf;+                xlsConvertFont(f);+				s = xls_addFont(pWB,f);+				if(xls_debug) {+					printf(" height: %d\n", f->height);+					printf("   flag: 0x%x\n", f->flag);+					printf("  color: 0x%x\n", f->color);+					printf(" weight: %d\n", f->bold);+					printf("escapem: 0x%x\n", f->escapement);+					printf("underln: 0x%x\n", f->underline);+					printf(" family: 0x%x\n", f->family);+					printf("charset: 0x%x\n", f->charset);+					if(s) printf("   name: %s\n", s);+				}+			}+			break;++        case XLS_RECORD_FORMAT:+            xlsConvertFormat((FORMAT *)buf);+            xls_addFormat(pWB,(FORMAT*)buf);+            break;++		case XLS_RECORD_STYLE:+			if(xls_debug) {+				struct { unsigned short idx; unsigned char ident; unsigned char lvl; } *styl;+				styl = (void *)buf;++				printf("    idx: 0x%x\n", styl->idx & 0x07FF);+				if(styl->idx & 0x8000) {+					printf("  ident: 0x%x\n", styl->ident);+					printf("  level: 0x%x\n", styl->lvl);+				} else {+					BYTE *s = get_string(&buf[2], 1, pWB->is5ver, pWB->charset);+					printf("  name=%s\n", s);+				}+			}+			break;++        case XLS_RECORD_PALETTE:+			if(xls_debug > 10) {+				unsigned char *p = buf + 2;+				int idx, len;++				len = *(WORD_UA *)buf;+				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;+				}+			}+			break;++		case XLS_RECORD_1904:+			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);+			}+			break;+		+		case XLS_RECORD_DEFINEDNAME:+			printf("DEFINEDNAME: ");+			for(int i=0; i<bof1.size; ++i) printf("%2.2x ", buf[i]);+			printf("\n");+			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)+			{+				//xls_showBOF(&bof1);+				printf("    Not Processed in parseWoorkBook():  BOF=0x%4.4X size=%d\n", bof1.id, bof1.size);+			}+            break;+        }+		free(buf);++        bof2=bof1;+		once=1;+    }+    while ((!pWB->olestr->eof)&&(bof1.id!=XLS_RECORD_EOF));+}+++void xls_preparseWorkSheet(xlsWorkSheet* pWS)+{+    BOF tmp;+    BYTE* buf;++    verbose ("xls_preparseWorkSheet");++    ole2_seek(pWS->workbook->olestr,pWS->filepos);+    do+    {+		size_t read;+        read = ole2_read(&tmp, 1,4,pWS->workbook->olestr);+		assert(read == 4);+        xlsConvertBof(&tmp);+        buf=(BYTE *)malloc(tmp.size);+        read = ole2_read(buf, 1,tmp.size,pWS->workbook->olestr);+		assert(read == tmp.size);+        switch (tmp.id)+        {+        case XLS_RECORD_DEFCOLWIDTH:+            pWS->defcolwidth=xlsShortVal(*(WORD_UA *)buf)*256;+            break;+        case XLS_RECORD_COLINFO:+            xlsConvertColinfo((COLINFO*)buf);+            xls_addColinfo(pWS,(COLINFO*)buf);+            break;+        case XLS_RECORD_ROW:+            xlsConvertRow((ROW*)buf);+            if (pWS->rows.lastcol<((ROW*)buf)->lcell)+                pWS->rows.lastcol=((ROW*)buf)->lcell;+            if (pWS->rows.lastrow<((ROW*)buf)->index)+                pWS->rows.lastrow=((ROW*)buf)->index;+            break;+        /* If the ROW record is incorrect or missing, infer the information from+         * cell data. */+        case XLS_RECORD_MULRK:+            if (pWS->rows.lastcol<xlsShortVal(((MULRK*)buf)->col) + (tmp.size - 6)/6 - 1)+                pWS->rows.lastcol=xlsShortVal(((MULRK*)buf)->col) + (tmp.size - 6)/6 - 1;+            if (pWS->rows.lastrow<xlsShortVal(((MULRK*)buf)->row))+                pWS->rows.lastrow=xlsShortVal(((MULRK*)buf)->row);+            break;+        case XLS_RECORD_MULBLANK:+            if (pWS->rows.lastcol<xlsShortVal(((MULBLANK*)buf)->col) + (tmp.size - 6)/2 - 1)+                pWS->rows.lastcol=xlsShortVal(((MULBLANK*)buf)->col) + (tmp.size - 6)/2 - 1;+            if (pWS->rows.lastrow<xlsShortVal(((MULBLANK*)buf)->row))+                pWS->rows.lastrow=xlsShortVal(((MULBLANK*)buf)->row);+            break;+        case XLS_RECORD_NUMBER:+        case XLS_RECORD_RK:+        case XLS_RECORD_LABELSST:+        case XLS_RECORD_BLANK:+        case XLS_RECORD_LABEL:+        case XLS_RECORD_FORMULA:+        case XLS_RECORD_FORMULA_ALT:+        case XLS_RECORD_BOOLERR:+            if (pWS->rows.lastcol<xlsShortVal(((COL*)buf)->col))+                pWS->rows.lastcol=xlsShortVal(((COL*)buf)->col);+            if (pWS->rows.lastrow<xlsShortVal(((COL*)buf)->row))+                pWS->rows.lastrow=xlsShortVal(((COL*)buf)->row);+            break;+        }+        free(buf);+    }+    while ((!pWS->workbook->olestr->eof)&&(tmp.id!=XLS_RECORD_EOF));+}++void xls_formatColumn(xlsWorkSheet* pWS)+{+    DWORD i,t,ii;+    DWORD fcol,lcol;++    for (i=0;i<pWS->colinfo.count;i++)+    {+        if (pWS->colinfo.col[i].first<=pWS->rows.lastcol)+            fcol=pWS->colinfo.col[i].first;+        else+            fcol=pWS->rows.lastcol;++        if (pWS->colinfo.col[i].last<=pWS->rows.lastcol)+            lcol=pWS->colinfo.col[i].last;+        else+            lcol=pWS->rows.lastcol;++        for (t=fcol;t<=lcol;t++) {+            for (ii=0;ii<=pWS->rows.lastrow;ii++)+            {+                if (pWS->colinfo.col[i].flags&1)+                    pWS->rows.row[ii].cells.cell[t].isHidden=1;+                pWS->rows.row[ii].cells.cell[t].width=pWS->colinfo.col[i].width;+            }+        }+    }+}++void xls_parseWorkSheet(xlsWorkSheet* pWS)+{+    BOF tmp;+    BYTE* buf;+	long offset = pWS->filepos;+	int continueRec = 0;++	struct st_cell_data *cell;+	xlsWorkBook *pWB = pWS->workbook;++    verbose ("xls_parseWorkSheet");++    xls_preparseWorkSheet(pWS);+	// printf("size=%d fatpos=%d)\n", pWS->workbook->olestr->size, pWS->workbook->olestr->fatpos);++    xls_makeTable(pWS);+    xls_formatColumn(pWS);++	cell = (void *)0;+    ole2_seek(pWS->workbook->olestr,pWS->filepos);+    do+    {+		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);+		}+        ole2_read(&tmp, 1,4,pWS->workbook->olestr);+        xlsConvertBof((BOF *)&tmp);+        buf=(BYTE *)malloc(tmp.size);+        ole2_read(buf, 1,tmp.size,pWS->workbook->olestr);+		offset += 4 + tmp.size;++		if(xls_debug)+			xls_showBOF(&tmp);++        switch (tmp.id)+        {+        case XLS_RECORD_EOF:+            break;+        case XLS_RECORD_MERGEDCELLS:+            xls_mergedCells(pWS,&tmp,buf);+            break;+        case XLS_RECORD_ROW:+			if(xls_debug > 10) printf("ROW: %x at pos=%ld\n", tmp.id, lastPos);+            xlsConvertRow((ROW *)buf);+            xls_addRow(pWS,(ROW*)buf);+            break;+		case XLS_RECORD_DEFCOLWIDTH:+			if(xls_debug > 10) printf("DEFAULT COL WIDTH: %d\n", *(WORD_UA *)buf);+			break;+		case XLS_RECORD_DEFAULTROWHEIGHT:+			if(xls_debug > 10) printf("DEFAULT ROW Height: 0x%x %d\n", ((WORD_UA *)buf)[0], ((WORD_UA *)buf)[1]);+			break;+		case XLS_RECORD_DBCELL:+			if(xls_debug > 10) {+				DWORD *foo = (DWORD_UA *)buf;+                WORD *goo;+				int i;+                printf("DBCELL: size %d\n", tmp.size);+				printf("DBCELL OFFSET=%4.4u -> ROW %ld\n", foo[0], lastPos-foo[0]);+				++foo;+				goo = (WORD *)foo;+				for(i=0; i<5; ++i) printf("goo[%d]=%4.4x %u\n", i, goo[i], goo[i]);+			}+			break;+        case XLS_RECORD_INDEX:+			if(xls_debug > 10) {+				DWORD *foo = (DWORD_UA *)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]);+			}+#if 0+			0	4 4	4 8	4+			12	4 16	4∙nm+			Not used Index to first used row (rf, 0-based) Index to first row of unused tail of sheet (rl, last used row + 1, 0-based)+			Absolute stream position of the DEFCOLWIDTH record (➜5.32) of the current sheet. If this record does not exist, the offset points to the record at the position where the DEFCOLWIDTH record would occur.+			Array of nm absolute stream positions to the DBCELL record (➜5.29) of each Row Block+#endif+            break;+        case XLS_RECORD_MULRK:+        case XLS_RECORD_MULBLANK:+        case XLS_RECORD_NUMBER:+        case XLS_RECORD_BOOLERR:+        case XLS_RECORD_RK:+        case XLS_RECORD_LABELSST:+        case XLS_RECORD_BLANK:+        case XLS_RECORD_LABEL:+        case XLS_RECORD_FORMULA:+        case XLS_RECORD_FORMULA_ALT:+            cell = xls_addCell(pWS,&tmp,buf);+            break;+		case XLS_RECORD_ARRAY:+			if(formula_handler) formula_handler(tmp.id, tmp.size, buf);+			break;++		case XLS_RECORD_STRING:+			if(cell && (cell->id == XLS_RECORD_FORMULA || cell->id == XLS_RECORD_FORMULA_ALT)) {+				cell->str = get_string(buf, (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:+		  printBOF:+			if(xls_debug)+			{+				//xls_showBOF(&tmp);+				printf("   [%d:%d]: 0x%X at pos=%lu size=%u\n", xlsShortVal(((COL*)buf)->row), xlsShortVal(((COL*)buf)->col), tmp.id, lastPos, tmp.size);+			}+            break;+        }+        free(buf);+    }+    while ((!pWS->workbook->olestr->eof)&&(tmp.id!=XLS_RECORD_EOF));+}++xlsWorkSheet * xls_getWorkSheet(xlsWorkBook* pWB,int num)+{+    xlsWorkSheet * pWS;+    verbose ("xls_getWorkSheet");+    pWS=(xlsWorkSheet *)calloc(1, sizeof(xlsWorkSheet));+    if (pWS != NULL) {+      pWS->filepos=pWB->sheets.sheet[num].filepos;+      pWS->workbook=pWB;+      pWS->rows.lastcol=0;+      pWS->rows.lastrow=0;+      pWS->colinfo.count=0;+    }+    return(pWS);+}++xlsWorkBook* xls_open(const char *file,const char* charset)+{+    xlsWorkBook* pWB;+    OLE2*		ole;++    pWB=(xlsWorkBook*)calloc(1, sizeof(xlsWorkBook));+    verbose ("xls_open");++    if (pWB == NULL) {+      return NULL;+    }++    // open excel file+    if (!(ole=ole2_open((BYTE *)file)))+    {+        if(xls_debug) printf("File \"%s\" not found\n",file);+		free(pWB);+        return(NULL);+    }++    if ((pWB->olestr=ole2_fopen(ole, (BYTE *)"\005SummaryInformation")))+    {+        pWB->summary = calloc(1,4096);+		ole2_read(pWB->summary, 4096, 1, pWB->olestr);+		ole2_fclose(pWB->olestr);+	}++    if ((pWB->olestr=ole2_fopen(ole, (BYTE *)"\005DocumentSummaryInformation")))+    {+        pWB->docSummary = calloc(1,4096);+		ole2_read(pWB->docSummary, 4096, 1, pWB->olestr);+		ole2_fclose(pWB->olestr);+	}++#if 0+	if(xls_debug) {+		printf("summary=%d docsummary=%d\n", pWB->summary ? 1 : 0, pWB->docSummary ? 1 : 0);+		xlsSummaryInfo *si = xls_summaryInfo(pWB);+		printf("title=%s\n", si->title);+		printf("subject=%s\n", si->subject);+		printf("author=%s\n", si->author);+		printf("keywords=%s\n", si->keywords);+		printf("comment=%s\n", si->comment);+		printf("lastAuthor=%s\n", si->lastAuthor);+		printf("appName=%s\n", si->appName);+		printf("category=%s\n", si->category);+		printf("manager=%s\n", si->manager);+		printf("company=%s\n", si->company);+	}+#endif++    // open Workbook+    if (!(pWB->olestr=ole2_fopen(ole,(BYTE *)"Workbook")) && !(pWB->olestr=ole2_fopen(ole,(BYTE *)"Book")))+    {+        if(xls_debug) printf("Workbook not found\n");+        ole2_close(ole);+		free(pWB);+        return(NULL);+    }+++    pWB->sheets.count=0;+    pWB->xfs.count=0;+    pWB->fonts.count=0;+    pWB->charset = (char *)malloc(strlen(charset) * sizeof(char)+1);+    strcpy(pWB->charset, charset);+    xls_parseWorkBook(pWB);++    return(pWB);+}++xlsRow *xls_row(xlsWorkSheet* pWS, WORD cellRow)+{+    struct st_row_data *row;++    if(cellRow > pWS->rows.lastrow) return NULL;+    row = &pWS->rows.row[cellRow];++    return row;+}++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;++    return &row->cells.cell[cellCol];+}++void xls_close_WB(xlsWorkBook* pWB)+{+	OLE2*		ole;++	verbose ("xls_close");++	if(!pWB) return;++    // OLE first+	ole=pWB->olestr->ole;+	+	ole2_fclose(pWB->olestr);++	ole2_close(ole);++    // WorkBook+    free(pWB->charset);++    // Sheets+    {+        DWORD i;+        for(i=0; i<pWB->sheets.count; ++i) {+            free(pWB->sheets.sheet[i].name);+        }+        free(pWB->sheets.sheet);+    }++    // SST+    {+        DWORD i;+        for(i=0; i<pWB->sst.count; ++i) {+            free(pWB->sst.string[i].str);+        }+        free(pWB->sst.string);+    }++    // xfs+    {+        free(pWB->xfs.xf);+    }++    // fonts+    {+        DWORD i;+        for(i=0; i<pWB->fonts.count; ++i) {+            free(pWB->fonts.font[i].name);+        }+        free(pWB->fonts.font);+    }++    // formats+    {+        DWORD i;+        for(i=0; i<pWB->formats.count; ++i) {+            free(pWB->formats.format[i].value);+        }+        free(pWB->formats.format);+    }++    // buffers+	if(pWB->summary)  free(pWB->summary);+	if(pWB->docSummary) free(pWB->docSummary);++	// TODO - free other dynamically allocated objects like string table??+	free(pWB);+}++void xls_close_WS(xlsWorkSheet* pWS)+{+	if(!pWS) return;++    // ROWS+    {+        DWORD i, j;+        for(j=0; j<=pWS->rows.lastrow; ++j) {+            struct st_row_data *row = &pWS->rows.row[j];+            for(i=0; i<row->cells.count; ++i) {+                free(row->cells.cell[i].str);+            }+            free(row->cells.cell);+        }+        free(pWS->rows.row);++    }++    // COLINFO+    {+        free(pWS->colinfo.col);+    }+    free(pWS);+}++const char* xls_getVersion(void)+{+    return PACKAGE_VERSION;+}++//+// http://poi.apache.org/hpsf/internals.html+// or google "DocumentSummaryInformation and UserDefined Property Sets" and look for MSDN hits+//++xlsSummaryInfo *xls_summaryInfo(xlsWorkBook* pWB)+{+	xlsSummaryInfo	*pSI;++	pSI = (xlsSummaryInfo *)calloc(1, sizeof(xlsSummaryInfo));+	xls_dumpSummary(pWB->summary, 1, pSI);+	xls_dumpSummary(pWB->docSummary, 0, pSI);++	return pSI;+}++void xls_close_summaryInfo(xlsSummaryInfo *pSI)+{+	if(!pSI) return;++	if(pSI->title)		free(pSI->title);+	if(pSI->subject)	free(pSI->subject);+	if(pSI->author)		free(pSI->author);+	if(pSI->keywords)	free(pSI->keywords);+	if(pSI->comment)	free(pSI->comment);+	if(pSI->lastAuthor)	free(pSI->lastAuthor);+	if(pSI->appName)	free(pSI->appName);+	if(pSI->category)	free(pSI->category);+	if(pSI->manager)	free(pSI->manager);+	if(pSI->company)	free(pSI->company);++	free(pSI);+}++void xls_dumpSummary(char *buf,int isSummary,xlsSummaryInfo *pSI) {+	header			*head;+	sectionList		*secList;+	propertyList	*plist;+	sectionHeader	*secHead;+	property		*prop;+	uint32_t i, j;++	if(!buf) return;	// perhaps the document was missing??++	head = (header *)buf;+	//printf("header: \n");+	//printf("  sig=%x\n", head->sig);+	//printf("  os=%x\n", head->os >> 16);+	//printf("  class=%8.8x%8.8x%8.8x%8.8x\n", head->format[0], head->format[1], head->format[2], head->format[3]);+	//printf("  count=%x\n", head->count);++	for(i=0; i<head->count; ++i) {+		secList = &head->secList[i];+		//printf("Section %d:\n", i);+		//printf("  class=%8.8x%8.8x%8.8x%8.8x\n", secList->format[0], secList->format[1], secList->format[2], secList->format[3]);+		//printf("  offset=%d (now at %ld\n", secList->offset, (char *)secList - (char *)buf + sizeof(sectionList));+++		secHead = (sectionHeader *)((char *)head + secList->offset);+		//printf("  len=%d\n", secHead->length);+		//printf("  properties=%d\n", secHead->numProperties);+		for(j=0; j<secHead->numProperties; ++j) {+			BYTE **s;++			plist = &secHead->properties[j];+			//printf("      ---------\n");+			//printf("      propID=%d offset=%d\n", plist->propertyID, plist->sectionOffset);+			prop = (property *)((char *)secHead + plist->sectionOffset);+			//printf("      propType=%d\n", prop->propertyID);++			switch(prop->propertyID) {+			case 2:+				//printf("      xlsShortVal=%x\n", *(uint16_t *)prop->data);+				break;+			case 3:+				//printf("      wordVal=%x\n", *(uint32_t *)prop->data);+				break;+			case 30:+				//printf("      longVal=%llx\n", *(uint64_t *)prop->data);+				//printf("      s[%u]=%s\n", *(uint32_t  *)prop->data, (char *)prop->data + 4);+				if(isSummary) {+					switch(plist->propertyID) {+					case 2:		s = &pSI->title;		break;+					case 3:		s = &pSI->subject;		break;+					case 4:		s = &pSI->author;		break;+					case 5:		s = &pSI->keywords;		break;+					case 6:		s = &pSI->comment;		break;+					case 8:		s = &pSI->lastAuthor;	break;+					case 18:	s = &pSI->appName;		break;+					default:	s = NULL;				break;+					}+				} else {+					switch(plist->propertyID) {+					case 2:		s = &pSI->category;		break;+					case 14:	s = &pSI->manager;		break;+					case 15:	s = &pSI->company;		break;+					default:	s = NULL;				break;+					}+				}+				if(s) *s = (BYTE *)strdup((char *)prop->data + 4);+				break;+			case 64:+				//printf("      longVal=%llx\n", *(uint64_t *)prop->data);+				break;+			case 65:+#if 0+				{+				uint32_t k;+				for(k=0; k<*(uint32_t  *)prop->data; ++k) {+				unsigned char *t = (unsigned char *)prop->data + 4 + k;+				printf(" %2.2x(%c)", *t, *t);+				}+				printf("\n");+				}+#endif+				break;+			default:+				//printf("      UNKNOWN!\n");+				break;+			}+		}+	}+}++void xls_set_formula_hander(xls_formula_handler handler)+{+	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+++++
+ lib/libxls/src/xlstool.c view
@@ -0,0 +1,838 @@+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *+ *+ * This file is part of libxls -- A multiplatform, C/C++ library+ * for parsing Excel(TM) files.+ *+ * Redistribution and use in source and binary forms, with or without modification, are+ * permitted provided that the following conditions are met:+ *+ *    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 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.+ *+ * Copyright 2004 Komarov Valery+ * Copyright 2006 Christophe Leitienne+ * Copyright 2013 Bob Colbert+ * Copyright 2008-2013 David Hoerl+ *+ */++#include "config.h"++#include <math.h>+#include <sys/types.h>+#include <wchar.h>+#include <stdio.h>++#ifdef HAVE_ICONV+#include <iconv.h>+#else+#include <locale.h>+#endif++#include <stdlib.h>+#include <errno.h>+#include <memory.h>+#include <string.h>++//#include "xls.h"+#include "libxls/xlstypes.h"+#include "libxls/xlsstruct.h"+#include "libxls/xlstool.h"+#include "libxls/brdb.h"+#include "libxls/endian.h"++extern int xls_debug;++static void xls_showBOUNDSHEET(void* bsheet);++static const DWORD colors[] =+    {+        0x000000,+        0xFFFFFF,+        0xFF0000,+        0x00FF00,+        0x0000FF,+        0xFFFF00,+        0xFF00FF,+        0x00FFFF,+        0x800000,+        0x008000,+        0x000080,+        0x808000,+        0x800080,+        0x008080,+        0xC0C0C0,+        0x808080,+        0x9999FF,+        0x993366,+        0xFFFFCC,+        0xCCFFFF,+        0x660066,+        0xFF8080,+        0x0066CC,+        0xCCCCFF,+        0x000080,+        0xFF00FF,+        0xFFFF00,+        0x00FFFF,+        0x800080,+        0x800000,+        0x008080,+        0x0000FF,+        0x00CCFF,+        0xCCFFFF,+        0xCCFFCC,+        0xFFFF99,+        0x99CCFF,+        0xFF99CC,+        0xCC99FF,+        0xFFCC99,+        0x3366FF,+        0x33CCCC,+        0x99CC00,+        0xFFCC00,+        0xFF9900,+        0xFF6600,+        0x666699,+        0x969696,+        0x003366,+        0x339966,+        0x003300,+        0x333300,+        0x993300,+        0x993366,+        0x333399,+        0x333333+    };++#if HAVE_ASPRINTF != 1++#include <stdarg.h>++#ifdef MSDN+static int asprintf(char **ret, const char *format, ...)+{+	int i, size=100;+    char *p, *np;++	va_list ap;++	if ((p = (char *)malloc(size)) == NULL)+        return -1;++    while (1) {+	    va_start(ap, format); ++	    i = _vsnprintf(p, size, format, ap);++	    va_end(ap);++        if (i > -1 && i < size)+        {+            i++;+            break;+        }++        if (i > -1)     /* glibc 2.1 */+            size = i+1; /* precisely what is needed */+        else            /* glibc 2.0 */+            size *= 2;  /* twice the old size */++        if ((np = realloc (p, size)) == NULL) {+            free(p);+            return -1;+        } else {+            p = np;+        }+    }++	*ret = p;+	return i > 255 ? 255 : i;+}++#else++static int asprintf(char **ret, const char *format, ...)+{+	int i;+    char *str;++	va_list ap;++	va_start(ap, format); ++	i = vsnprintf(NULL, 0, format, ap) + 1;+	str = (char *)malloc(i);+	i = vsnprintf(str, i, format, ap);++	va_end(ap);++	*ret = str;+	return i > 255 ? 255 : i;+}+#endif++#endif+++void dumpbuf(BYTE* fname,long size,BYTE* buf)+{+    FILE *f = fopen((char *)fname, "wb");+    fwrite (buf, 1, size, f);+    fclose(f);++}++// Display string if in debug mode+void verbose(char* str)+{+    if (xls_debug)+        printf("libxls : %s\n",str);+}++BYTE *utf8_decode(BYTE *str, DWORD len, char *encoding)+{+	int utf8_chars = 0;+	BYTE *ret;+    DWORD i;+	+	for(i=0; i<len; ++i) {+		if(str[i] & (BYTE)0x80) {+			++utf8_chars;+		}+	}+	+	if(utf8_chars == 0 || strcmp(encoding, "UTF-8")) {+		ret = (BYTE *)malloc(len+1);+		memcpy(ret, str, len);+		ret[len] = 0;+	} else {+        DWORD i;+        BYTE *out;+		// UTF-8 encoding inline+		ret = (BYTE *)malloc(len+utf8_chars+1);+		out = ret;+		for(i=0; i<len; ++i) {+			BYTE c = str[i];+			if(c & (BYTE)0x80) {+				*out++ = (BYTE)0xC0 | (c >> 6);+				*out++ = (BYTE)0x80 | (c & 0x3F);+			} else {+				*out++ = c;+			}+		}+		*out = 0;+	}++	return ret;+}++// Convert unicode string to to_enc encoding+BYTE* unicode_decode(const BYTE *s, int len, size_t *newlen, const char* to_enc)+{+#ifdef HAVE_ICONV+	// Do iconv conversion+#ifdef AIX+    const char *from_enc = "UTF-16le";+#else+    const char *from_enc = "UTF-16LE";+#endif+    BYTE* outbuf = 0;++    if(s && len && from_enc && to_enc)+    {+        size_t outlenleft = len;+        int outlen = len;+        size_t inlenleft = len;+        iconv_t ic = iconv_open(to_enc, from_enc);+        BYTE* src_ptr = (BYTE*) s;+        BYTE* out_ptr = 0;++        if(ic == (iconv_t)-1)+        {+            // Something went wrong.+            if (errno == EINVAL)+            {+                if (!strcmp(to_enc, "ASCII"))+                {+                    ic = iconv_open("UTF-8", from_enc);+                    if(ic == (iconv_t)-1)+                    {+                        printf("conversion from '%s' to '%s' not available", from_enc, to_enc);+                        return outbuf;+                    }+                }+            }+            else+            {+                printf ("iconv_open: error=%d", errno);+                return outbuf;+            }+        }+        size_t st; +        outbuf = (BYTE*)malloc(outlen + 1);++		if(outbuf)+        {+            out_ptr = (BYTE*)outbuf;+            while(inlenleft)+            {+                st = iconv(ic, (char **)&src_ptr, &inlenleft, (char **)&out_ptr,(size_t *) &outlenleft);+                if(st == (size_t)(-1))+                {+                    if(errno == E2BIG)+                    {+                        size_t diff = out_ptr - outbuf;+                        outlen += inlenleft;+                        outlenleft += inlenleft;+                        outbuf = (BYTE*)realloc(outbuf, outlen + 1);+                        if(!outbuf)+                        {+                            break;+                        }+                        out_ptr = outbuf + diff;+                    }+                    else+                    {+                        free(outbuf), outbuf = NULL;+                        break;+                    }+                }+            }+        }+        iconv_close(ic);+        outlen -= outlenleft;++        if (newlen)+        {+            *newlen = outbuf ? outlen : 0;+        }+        if(outbuf)+        {+            outbuf[outlen] = 0;+        }+    }+    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;++    w = (wchar_t*)malloc((len+1)*sizeof(wchar_t));++    for(i=0; i<len; i++)+    {+        w[i]=xlsShortVal(x[i]);+    }+    w[len] = '\0';++    count = wcstombs(NULL, w, 0);++	if (count <= 0) {+		if (newlen) *newlen = 0;+		return NULL;+	}++	converted = calloc(count+1, sizeof(char));+	count2 = wcstombs(converted, w, count);+    free(w);+	if (count2 <= 0) {+		printf("wcstombs failed (%d)\n", len);+		if (newlen) *newlen = 0;+		return converted;+	} else {+		if (newlen) *newlen = count2;+		return converted;+	}+#endif+}++// Read and decode string+BYTE* get_string(BYTE *s, BYTE is2, BYTE is5ver, char *charset)+{+    WORD ln;+    DWORD ofs;+    BYTE flag;+    BYTE* str;+    BYTE* ret;+	+	flag = 0;+    str=s;++    ofs=0;++    if (is2) {+		// length is two bytes+        ln=xlsShortVal(*(WORD_UA *)str);+        ofs+=2;+    } else {+		// single byte length+        ln=*(BYTE*)str;+        ofs++;+    }++	if(!is5ver) {+		// unicode strings have a format byte before the string+		flag=*(BYTE*)(str+ofs);+		ofs++;+	}+    if (flag&0x8)+    {+		// WORD rt;+        // rt=*(WORD*)(str+ofs); // unused+        ofs+=2;+    }+    if (flag&0x4)+    {+		// DWORD sz;+        // sz=*(DWORD*)(str+ofs); // unused+        ofs+=4;+    }+    if(flag & 0x1)+    {+		size_t new_len = 0;+        ret = unicode_decode(str+ofs,ln*2, &new_len,charset);+    } else {+		ret = utf8_decode((str+ofs), ln, charset);+    }++#if 0	// debugging+	if(xls_debug == 100) {+		ofs += (flag & 0x1) ? ln*2 : ln;++		printf("ofs=%d ret[0]=%d\n", ofs, *ret);+		{+			unsigned char *ptr;+			+			ptr = ret;+			+			printf("%x %x %x %x %x %x %x %x\n", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7] );+			printf("%s\n", ret);+		}+	}+#endif++    return ret;+}++DWORD xls_getColor(const WORD color,WORD def)+{+    int cor=8;+    int size = 64 - cor;+    int max = size;+    WORD idx=color;+    if( idx >= cor)+        idx -= cor;+    if( idx < max )+    {+        return colors[idx];+    }+    else+        return colors[def];+}+++void xls_showBookInfo(xlsWorkBook* pWB)+{+    verbose("BookInfo");+    printf("  is5ver: %i\n",pWB->is5ver);+    printf("codepage: %i\n",pWB->codepage);+    printf("    type: %.4X ",pWB->type);+    switch (pWB->type)+    {+    case 0x5:+        printf("Workbook globals\n");+        break;+    case 0x6:+        printf("Visual Basic module\n");+        break;+    case 0x10:+        printf("Worksheet\n");+        break;+    case 0x20:+        printf("Chart\n");+        break;+    case 0x40:+        printf("BIFF4 Macro sheet\n");+        break;+    case 0x100:+        printf("BIFF4W Workbook globals\n");+        break;+    }+    printf("------------------- END BOOK INFO---------------------------\n");+}+++void xls_showBOF(BOF* bof)+{+    printf("----------------------------------------------\n");+    verbose("BOF");+    printf("   ID: %.4Xh %s (%s)\n",bof->id,brdb[get_brbdnum(bof->id)].name,brdb[get_brbdnum(bof->id)].desc);+    printf("   Size: %i\n",bof->size);+}++#if 0+static void xls_showBOUNDSHEET(BOUNDSHEET* bsheet)+{+    switch (bsheet->type & 0x000f)+    {+    case 0x0000:+        /* worksheet or dialog sheet */+        verbose ("85: Worksheet or dialog sheet");+        break;+    case 0x0001:+        /* Microsoft Excel 4.0 macro sheet */+        verbose ("85: Microsoft Excel 4.0 macro sheet");+        break;+    case 0x0002:+        /* Chart */+        verbose ("85: Chart sheet");+        break;+    case 0x0006:+        /* Visual Basic module */+        verbose ("85: Visual Basic sheet");+        break;+    default:+        break;+    }+    printf("    Pos: %Xh\n",bsheet->filepos);+    printf("  flags: %.4Xh\n",bsheet->type);+    //	printf("   Name: [%i] %s\n",bsheet->len,bsheet->name);+}+#endif++void xls_showROW(struct st_row_data* row)+{+    verbose("ROW");+    printf("    Index: %i \n",row->index);+    printf("First col: %i \n",row->fcell);+    printf(" Last col: %i \n",row->lcell);+    printf("   Height: %i (1/20 px)\n",row->height);+    printf("    Flags: %.4X \n",row->flags);+    printf("       xf: %i \n",row->xf);+    printf("----------------------------------------------\n");+}++void xls_showColinfo(struct st_colinfo_data* col)+{+    verbose("COLINFO");+    printf("First col: %i \n",col->first);+    printf(" Last col: %i \n",col->last);+    printf("    Width: %i (1/256 px)\n",col->width);+    printf("       XF: %i \n",col->xf);+    printf("    Flags: %i (",col->flags);+    if (col->flags & 0x1)+        printf("hidden ");+    if (col->flags & 0x700)+        printf("outline ");+    if (col->flags & 0x1000)+        printf("collapsed ");+    printf(")\n");+    printf("----------------------------------------------\n");+}++void xls_showCell(struct st_cell_data* cell)+{+    printf("  -----------\n");+    printf("     ID: %.4Xh %s (%s)\n",cell->id, brdb[get_brbdnum(cell->id)].name, brdb[get_brbdnum(cell->id)].desc);+    printf("   Cell: %c:%u  [%u:%u]\n",cell->col+'A',cell->row+1,cell->col,cell->row);+//    printf("   Cell: %u:%u\n",cell->col+1,cell->row+1);+    printf("     xf: %i\n",cell->xf);+	if(cell->id == XLS_RECORD_BLANK) {+		//printf("BLANK_CELL!\n");+		return;+	}+    printf(" double: %f\n",cell->d);+    printf("    int: %d\n",cell->l);+    if (cell->str!=NULL)+        printf("    str: %s\n",cell->str);+}+++void xls_showFont(struct st_font_data* font)+{++    printf("      name: %s\n",font->name);+    printf("    height: %i\n",font->height);+    printf("      flag: %.4X\n",font->flag);+    printf("     color: %.6X\n",font->color);+    printf("      bold: %i\n",font->bold);+    printf("escapement: %i\n",font->escapement);+    printf(" underline: %i\n",font->underline);+    printf("    family: %i\n",font->family);+    printf("   charset: %i\n",font->charset);++}+#if 0+typedef struct st_format+	{+		long count;		//Count of FORMAT's+		struct st_format_data+		{+			WORD index;+			char *value;+		}+		* format;+	}+	st_format;+#endif++void xls_showFormat(struct st_format_data* frmt)+{+	printf("    index : %u\n", frmt->index);+    printf("     value: %s\n", frmt->value);+}++void xls_showXF(XF8* xf)+{+	static int idx;+	+    printf("      Index: %u\n",idx++);+    printf("       Font: %u\n",xf->font);+    printf("     Format: %u\n",xf->format);+    printf("       Type: 0x%x\n",xf->type);+    printf("      Align: 0x%x\n",xf->align);+    printf("   Rotation: 0x%x\n",xf->rotation);+    printf("      Ident: 0x%x\n",xf->ident);+    printf("   UsedAttr: 0x%x\n",xf->usedattr);+    printf("  LineStyle: 0x%x\n",xf->linestyle);+    printf("  Linecolor: 0x%x\n",xf->linecolor);+    printf("GroundColor: 0x%x\n",xf->groundcolor);+}++BYTE *xls_getfcell(xlsWorkBook* pWB,struct st_cell_data* cell,WORD *label)+{+    struct st_xf_data *xf;+	WORD	len;+    char	*ret = NULL;++    xf=&pWB->xfs.xf[cell->xf];++    switch (cell->id)+    {+    case XLS_RECORD_LABELSST:+		//printf("WORD: %u short: %u str: %s\n", *label, xlsShortVal(*label), pWB->sst.string[xlsShortVal(*label)].str );+        asprintf(&ret,"%s",pWB->sst.string[xlsShortVal(*label)].str);+        break;+    case XLS_RECORD_BLANK:+    case XLS_RECORD_MULBLANK:+        asprintf(&ret, "");+        break;+    case XLS_RECORD_LABEL:+		len = xlsShortVal(*label);+        label++;+		if(pWB->is5ver) {+			asprintf(&ret,"%.*s", len, (char *)label);+			//printf("Found BIFF5 string of len=%d \"%s\"\n", len, ret);+		} else+		if ((*(BYTE *)label & 0x01) == 0) {+			ret = (char *)utf8_decode((BYTE *)label + 1, len, pWB->charset);+		} else {+			size_t newlen;+		    ret = (char *)unicode_decode((BYTE *)label + 1, len*2, &newlen, pWB->charset);+		}+        break;+    case XLS_RECORD_RK:+    case XLS_RECORD_NUMBER:+        asprintf(&ret,"%lf", cell->d);+		break;+		//		if( RK || MULRK || NUMBER || FORMULA)+		//		if (cell->id==0x27e || cell->id==0x0BD || cell->id==0x203 || 6 (formula))+    default:+        switch (xf->format)+        {+        case 0:+            asprintf(&ret,"%d",(int)cell->d);+            break;+        case 1:+            asprintf(&ret,"%d",(int)cell->d);+            break;+        case 2:+            asprintf(&ret,"%.1f",cell->d);+            break;+        case 9:+            asprintf(&ret,"%d",(int)cell->d);+            break;+        case 10:+            asprintf(&ret,"%.2f",cell->d);+            break;+        case 11:+            asprintf(&ret,"%.1e",cell->d);+            break;+        case 14:+			//ret=ctime(cell->d);+			asprintf(&ret,"%.0f",cell->d);+            break;+        default:+			// asprintf(&ret,"%.4.2f (%i)",cell->d,xf->format);break;+            asprintf(&ret,"%.2f",cell->d);+            break;+        }+        break;+    }++    return (BYTE *)ret;+}++char* xls_getCSS(xlsWorkBook* pWB)+{+    char color[255];+    char* align;+    char* valign;+    char borderleft[255];+    char borderright[255];+    char bordertop[255];+    char borderbottom[255];+    char italic[255];+    char underline[255];+    char bold[255];+    WORD size;+    char fontname[255];+    struct st_xf_data* xf;+    DWORD background;+    DWORD i;++    char *ret = malloc(65535);+    char *buf = malloc(4096);+	ret[0] = '\0';++    for (i=0;i<pWB->xfs.count;i++)+    {+        xf=&pWB->xfs.xf[i];+        switch ((xf->align & 0x70)>>4)+        {+        case 0:+            valign=(char*)"top";+            break;+        case 1:+            valign=(char*)"middle";+            break;+        case 2:+            valign=(char*)"bottom";+            break;+            //			case 3: valign=(char*)"right"; break;+            //			case 4: valign=(char*)"right"; break;+        default:+            valign=(char*)"middle";+            break;+        }++        switch (xf->align & 0x07)+        {+        case 1:+            align=(char*)"left";+            break;+        case 2:+            align=(char*)"center";+            break;+        case 3:+            align=(char*)"right";+            break;+        default:+            align=(char*)"left";+            break;+        }++        switch (xf->linestyle & 0x0f)+        {+        case 0:+            sprintf(borderleft,"%s", "");+            break;+        default:+            sprintf(borderleft,"border-left: 1px solid black;");+            break;+        }++        switch (xf->linestyle & 0x0f0)+        {+        case 0:+            sprintf(borderright,"%s", "");+            break;+        default:+            sprintf(borderright,"border-right: 1px solid black;");+            break;+        }++        switch (xf->linestyle & 0x0f00)+        {+        case 0:+            sprintf(bordertop,"%s", "");+            break;+        default:+            sprintf(bordertop,"border-top: 1px solid black;");+            break;+        }++        switch (xf->linestyle & 0x0f000)+        {+        case 0:+            sprintf(borderbottom,"%s", "");+            break;+        default:+            sprintf(borderbottom,"border-bottom: 1px solid Black;");+            break;+        }++        if (xf->font)+            sprintf(color,"color:#%.6X;",xls_getColor(pWB->fonts.font[xf->font-1].color,0));+        else+            sprintf(color,"%s", "");++        if (xf->font && (pWB->fonts.font[xf->font-1].flag & 2))+            sprintf(italic,"font-style: italic;");+        else+            sprintf(italic,"%s", "");++        if (xf->font && (pWB->fonts.font[xf->font-1].bold>400))+            sprintf(bold,"font-weight: bold;");+        else+            sprintf(bold,"%s", "");++        if (xf->font && (pWB->fonts.font[xf->font-1].underline))+            sprintf(underline,"text-decoration: underline;");+        else+            sprintf(underline,"%s", "");++        if (xf->font)+            size=pWB->fonts.font[xf->font-1].height/20;+        else+            size=10;++        if (xf->font)+            sprintf(fontname,"%s",pWB->fonts.font[xf->font-1].name);+        else+            sprintf(fontname,"Arial");++        background=xls_getColor((WORD)(xf->groundcolor & 0x7f),1);+        sprintf(buf,".xf%i{ font-size:%ipt;font-family: \"%s\";background:#%.6X;text-align:%s;vertical-align:%s;%s%s%s%s%s%s%s%s}\n",+                i,size,fontname,background,align,valign,borderleft,borderright,bordertop,borderbottom,color,italic,bold,underline);++		strcat(ret,buf);+    }+	ret = realloc(ret, strlen(ret)+1);+	free(buf);++    return ret;+}
+ stack-7.8.yaml view
@@ -0,0 +1,8 @@+flags: {}+packages:+- '.'+extra-deps:+- base-compat-0.9.1+- base-orphans-0.5.4+- getopt-generics-0.13+resolver: lts-2.22
+ stack.yaml view
@@ -0,0 +1,3 @@+resolver: lts-6.16+packages:+- '.'
+ test/Spec.hs view
@@ -0,0 +1,2 @@+main :: IO ()+main = putStrLn "Test suite not yet implemented"
+ xls.cabal view
@@ -0,0 +1,87 @@+name:                xls+version:             0.1.0+synopsis:            Parse Microsoft Excel xls files (BIFF/Excel 97-2004)+description:+ Parse Microsoft Excel spreadsheet files in @.xls@ file format+ (extension '.xls') more specifically known as 'BIFF/Excel 97-2004'.+ .+ The library is based on the C library+ 'https://sourceforge.net/projects/libxls'.++homepage: http://github.com/harendra-kumar/xls+license:             BSD3+license-file:        LICENSE+author:              Harendra Kumar+maintainer:          harendra.kumar@gmail.com+category:            Codec,Data,Parser,Spreadsheet+copyright:           2016 Harendra Kumar,+                     2004-2014 Authors of libxls+stability:           Experimental++build-type:          Simple+cabal-version:       >=1.10++extra-source-files:+    README.md+    stack.yaml+    stack-7.8.yaml+    lib/libxls/config/*.h+    lib/libxls/include/libxls/*.h+    lib/libxls/include/libxls/*.c.h++flag force-has-iconv+  description: force using iconv library on Windows+  manual: True+  default: False++library+  default-language:    Haskell2010+  ghc-options:         -Wall++  -- c99 also works but clang and gcc both support gnu99. We will have to use+  -- a configure script if better portability is required.+  -- _GNU_SOURCE is required to enable asprintf in glibc+  cc-options:          -std=gnu99 -D_GNU_SOURCE+  if flag(force-has-iconv)+    cc-options:        -DFORCE_HAS_ICONV++  hs-source-dirs:      lib+  exposed-modules:     Data.Xls+  build-depends:       base         >= 4     && < 5+                     , conduit      >= 1.1   && < 1.3+                     , filepath     >= 1.0   && < 1.5+                     , resourcet    >= 0.3   && < 1.2+                     , transformers >= 0.1   && < 0.6++  c-sources:           lib/libxls-wrapper.c,+                       lib/libxls/src/xlstool.c,+                       lib/libxls/src/endian.c,+                       lib/libxls/src/ole.c,+                       lib/libxls/src/xls.c++  include-dirs:        lib/libxls/config,+                       lib/libxls/include++executable xls2csv+  default-language:    Haskell2010+  hs-source-dirs:      bin+  main-is:             xls2csv.hs+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N+  build-depends:        base            >= 4     && < 5+                      , conduit         >= 1.1   && < 1.3+                      , resourcet       >= 0.3   && < 1.2+                      , transformers    >= 0.1   && < 0.6+                      , getopt-generics >= 0.11  && < 0.14+                      , xls++test-suite test+  default-language:    Haskell2010+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             Spec.hs+  build-depends:       base, xls+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N++source-repository head+  type:     git+  location: https://github.com/harendra-kumar/xls