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 +30/−0
- README.md +41/−0
- Setup.hs +2/−0
- bin/xls2csv.hs +20/−0
- lib/Data/Xls.hs +201/−0
- lib/libxls-wrapper.c +46/−0
- lib/libxls/config/config.h +10/−0
- lib/libxls/include/libxls/brdb.c.h +213/−0
- lib/libxls/include/libxls/brdb.h +58/−0
- lib/libxls/include/libxls/endian.h +62/−0
- lib/libxls/include/libxls/ole.h +173/−0
- lib/libxls/include/libxls/xls.h +73/−0
- lib/libxls/include/libxls/xlsstruct.h +534/−0
- lib/libxls/include/libxls/xlstool.h +52/−0
- lib/libxls/include/libxls/xlstypes.h +70/−0
- lib/libxls/src/endian.c +315/−0
- lib/libxls/src/ole.c +562/−0
- lib/libxls/src/xls.c +2184/−0
- lib/libxls/src/xlstool.c +838/−0
- stack-7.8.yaml +8/−0
- stack.yaml +3/−0
- test/Spec.hs +2/−0
- xls.cabal +87/−0
+ 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++[](https://travis-ci.org/harendra-kumar/xls)+[](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(¬e, 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