// Created by Yap Chun Wei // Version 1.0 (20 April 2006) // Version 1.1 (22 April 2006) // - Fixed bugs with compound files not being able to write files more than 65535 bytes. // - Fixed bugs with reading and writing to Excel files containing many strings. // Version 1.2 (30 April 2006) // - Added operator<< to pass BasicExcelCell to an output stream. // - Added Print() to BasicExcelWorksheet to print the worksheet to an output stream. // - Change BasicExcelCell Get functions to const functions. // - Rename BasicExcelWorksheet functions RenameWorkSheet() to Rename(). // Version 1.3 (10 May 2006) // - Fixed bugs with reading from Excel files containing Asian characters. // Version 1.4 (13 May 2006) // - Fixed bugs with reading and writing to Excel files containing many strings. // Version 1.5 (15 May 2006) // - Remove code for ExtSST because it was causing problems with reading and writing to Excel files containing many strings. // Version 1.6 (16 May 2006) // - Optimized code for reading and writing. // Version 1.7 (22 May 2006) // - Fixed code to remove some warnings. // - Fixed bug with BasicExcelWorksheet::Cell. // - Fixed bug with BasicExcel::UpdateWorksheets(). // Version 1.8 (23 May 2006) // - Fixed bug with reading Excel files containing many unicode strings. // - Fixed code to remove some warnings. // - Fixed variable code_ duplication in BoolErr. // - Minor changes to BasicExcelCell:Set functions. // Version 1.9 (24 May 2006) // - Changed name_ in Style from SmallString to LargeString. // - Fixed bug in BasicExcelCell::GetString and BasicExcelCell::GetWString. // - Minor changes to functions in BasicExcel and BasicExcelWorksheet which checks for unicode. // - Minor change to SmallString::Read. // Version 1.10 (30 May 2006) // - Fixed bug with reading Excel files containing many strings. // - Remove memory leaks. // Version 1.11 (2 June 2006) // - Fixed bug with reading and writing Excel files containing many unicode and ANSI strings. // Version 1.12 (6 June 2006) // - Fixed bug with reading and writing Excel files containing many unicode and ANSI strings. // Version 1.13 (1 August 2006) // - Changed BasicExcelCell::Get() so that it will get a stored double as an integer or vice versa if necessary. // - Changed BasicExcelCell::Get() so that it will not cause any errors if a string is empty. // - Changed BasicExcelCell::SetString() and BasicExcelCell::SetWString() so that it will not save an empty string. // Version 1.14 (6 August 2006) // - Fixed bug with reading Excel files that contain a null string. // Version 2.0 (September 2009, Martin Fuchs) // - extended to maintain font and format information when reading and writing Excel sheets // - XLSFormatManager, ExcelFont and CellFormat to edit fonts and formats // Version 2.1 (04.10.2009, Martin Fuchs) // - fixed memory leak in XLSFormatManager::get_font_idx() // - define macros and constants for cell and font properties // Version 2.2 (07.11.2009, Martin Fuchs) // - fixed VS2008 problem when reading sheets with formula fields // - added BasicExcel::Close() // - added CellFormat::get/set_text_props() and get/set_borderlines() // Version 2.3 (05.01.2010, Ami Castonguay/Martin Fuchs) // - fixed reference counting of Formula data structs // - support for shared formulas // - support for merged cells // - save formatting even if cell is empty // - flush fstream instead of closing it followed by open to prevent races in conjunction with virus scanners // - enable reading of XLS files exported by MacOS Numbers.app // Version 2.4 (24.01.2010, Long Wenbiao/Martin Fuchs) // - add second set_borderlines() overload // - add ExcelFont::set_italic(), CellFormat::set_wrapping() // - handle COLINFO // - miscellaneous fixes // Version 2.5 (01.01.2011, Martin Fuchs) // - dynamically allocate memory for unexpected high row/column values // - Unicode overloads for Load() and SaveAs() // - adjust to RKValues written by OpenOffice Calc // Version 3.0 (23.01.2011, Martin Fuchs) // - portability fixes to enable using the code in 64 Bit development environments // - in a Windows environment use the Windows API instead of the old CompoundFile class to access compound document files // - reduced memory consumption in BasicExcel data handling // - return current value string from formula cells // - don't preserve empty rows/columns at the end of sheets #ifndef BASICEXCEL_HPP #define BASICEXCEL_HPP //MF #if defined(_MSC_VER) && _MSC_VER<=1200 // VC++ 6.0 #pragma warning(disable: 4786) #define LONGINT __int64 #define LONGINT_CONST(x) x #define COMPOUNDFILE #else // newer Microsoft compilers #define LONGINT long long #define LONGINT_CONST(x) x##LL #define COMPOUNDFILE CompoundFile:: #ifdef _DEBUG #define _ITERATOR_DEBUG_LEVEL 0 // speedup iterator operations while debugging #endif #endif //MF type definitions of the Windows Compound Binary File Format (CBF) Specification typedef unsigned char BYTE; // 8 bit unsigned integer typedef unsigned short WORD; // 16 bit unsigned integer typedef short SHORT; // 16 bit signed integer typedef unsigned short USHORT; // 16 bit unsigned integer #ifdef _MSC_VER typedef unsigned long DWORD; // 32 bit unsigned integer typedef long LONG; // 32 bit signed integer typedef unsigned long ULONG; // 32 bit unsigned integer #else typedef unsigned int DWORD; // 32 bit unsigned integer typedef int LONG; // 32 bit signed integer typedef unsigned int ULONG; // 32 bit unsigned integer #endif typedef short OFFSET; typedef ULONG SECT; typedef ULONG FSINDEX; typedef USHORT FSOFFSET; typedef ULONG DFSIGNATURE; typedef WORD DFPROPTYPE; typedef ULONG CBF_SID; // renamed SID because of ambiguity with windows header files #ifndef GUID_DEFINED #define GUID_DEFINED typedef struct _GUID { ULONG Data1; USHORT Data2; USHORT Data3; BYTE Data4[8]; } GUID; #endif typedef GUID CLSID; // 16 bytes struct TIME_T { // FILETYPE DWORD dwLowDateTime; DWORD dwHighDateTime; }; #define DIFSECT 0xFFFFFFFC #define FATSECT 0xFFFFFFFD #define ENDOFCHAIN 0xFFFFFFFE #define FREESECT 0xFFFFFFFF #ifndef _WIN32 enum STGTY { STGTY_INVALID = 0, STGTY_STORAGE = 1, STGTY_STREAM = 2, STGTY_LOCKBYTES = 3, STGTY_PROPERTY = 4, STGTY_ROOT = 5 }; #endif enum DECOLOR { DE_RED = 0, DE_BLACK = 1 }; #if _MSC_VER>=1400 // VS 2005 #define _CRT_SECURE_NO_WARNINGS //MF #define _SCL_SECURE_NO_WARNINGS //MF #endif #include #include #include #include #include #include #include #include #include //MF using namespace std; // get facet from locale for GCC #ifndef _USE #define _USE(loc, fac) use_facet(loc) #endif #include //MF #ifndef _MSC_VER #include #endif #define UTF16 #ifdef UTF16 #define SIZEOFWCHAR_T 2 #else #define SIZEOFWCHAR_T sizeof(wchar_t) #endif //MF string conversion functions // Courtesy of Tom Widmer (VC++ MVP) inline std::string narrow_string(const std::wstring& str) { std::string ret; if (!str.empty()) { ret.resize(str.length()); typedef std::ctype CT; CT const& ct = std::_USE(std::locale(), CT); ct.narrow(&str[0], &*str.begin()+str.size(), '?', &ret[0]); } return ret; } inline std::wstring widen_string(const std::string& str) { std::wstring ret; if (!str.empty()) { ret.resize(str.length()); typedef std::ctype CT; CT const& ct = std::_USE(std::locale(), CT); ct.widen(&str[0], &*str.begin()+str.size(), &ret[0]); } return ret; } #ifdef _WIN32 #include #pragma comment(lib, "ole32") // MF namespace WinCompFiles { enum CF_RESULT { INVALID_SIZE = -6, FILE_NOT_FOUND = -4, DIRECTORY_NOT_EMPTY = -3, DIRECTORY_NOT_FOUND = -2, INVALID_PATH = -1, SUCCESS = 1 }; struct CompoundFile { CompoundFile(); ~CompoundFile(); // Compound File functions bool Create(const wchar_t* filename); bool Open(const wchar_t* filename, ios_base::openmode mode=ios_base::in|ios_base::out); bool Close(); bool IsOpen(); // File functions CF_RESULT MakeFile(const wchar_t* path); CF_RESULT FileSize(const wchar_t* path, ULONGLONG& size); CF_RESULT ReadFile(const wchar_t* path, char* data, ULONG size); CF_RESULT ReadFile(const wchar_t* path, vector&data); CF_RESULT WriteFile(const wchar_t* path, const char* data, ULONG size); CF_RESULT WriteFile(const wchar_t* path, const vector&data, ULONG size); // ANSI char functions bool Create(const char* filename); bool Open(const char* filename, ios_base::openmode mode=ios_base::in|ios_base::out); CF_RESULT MakeFile(const char* path); CF_RESULT FileSize(const char* path, ULONGLONG& size); CF_RESULT ReadFile(const char* path, char* data, ULONG size); CF_RESULT ReadFile(const char* path, vector& data); CF_RESULT WriteFile(const char* path, const char* data, ULONG size); CF_RESULT WriteFile(const char* path, const vector& data, ULONG size); private: IStorage* _pStg; }; } // namespace WinCompFiles #endif namespace YCompoundFiles { struct LittleEndian { #if defined(_MSC_VER) && _MSC_VER<=1200 // VC++ 6.0 #define READWRITE(Type) \ static void Read(const char* buffer, Type& retVal, size_t pos=0, int bytes=0) \ { \ retVal = Type(0); \ if (bytes == 0) bytes = sizeof(Type); \ for (size_t i=0; i>= 8; \ } \ } \ static void WriteString(char* buffer, Type* str, size_t pos=0, int bytes=0) \ { \ for (size_t i=0; i& buffer, Type& retVal, size_t pos=0, int bytes=0) \ { \ retVal = Type(0); \ if (bytes == 0) bytes = sizeof(Type); \ for (size_t i=0; i& buffer, Type* str, size_t pos=0, int bytes=0) \ { \ for (size_t i=0; i& buffer, Type val, size_t pos=0, int bytes=0) \ { \ if (bytes == 0) bytes = sizeof(Type); \ for (size_t i=0; i>= 8; \ } \ } \ static void WriteString(vector& buffer, Type* str, size_t pos=0, int bytes=0) \ { \ for (size_t i=0; i>= 8; } } static void WriteString(char* buffer, wchar_t* str, size_t pos=0, int bytes=0) { for (int i=0; i& buffer, wchar_t& retVal, size_t pos=0, int bytes=0) { retVal = wchar_t(0); if (bytes == 0) bytes = SIZEOFWCHAR_T; for (int i=0; i& buffer, wchar_t* str, size_t pos=0, int bytes=0) { for (int i=0; i& buffer, wchar_t val, size_t pos=0, int bytes=0) { if (bytes == 0) bytes = SIZEOFWCHAR_T; for (int i=0; i>= 8; } } static void WriteString(vector& buffer, wchar_t* str, size_t pos=0, int bytes=0) { for (int i=0; i static void Read(const char* buffer, Type& retVal, size_t pos=0, int bytes=0) { retVal = Type(0); if (bytes == 0) bytes = sizeof(Type); for (int i=0; i static void ReadString(const char* buffer, Type* str, size_t pos=0, int bytes=0) { for (int i=0; i static void Write(char* buffer, Type val, size_t pos=0, int bytes=0) { if (bytes == 0) bytes = sizeof(Type); for (int i=0; i>= 8; } } template static void WriteString(char* buffer, Type* str, size_t pos=0, int bytes=0) { for (int i=0; i static void Read(const vector& buffer, Type& retVal, size_t pos=0, int bytes=0) { retVal = Type(0); if (bytes == 0) bytes = sizeof(Type); for (int i=0; i static void ReadString(const vector& buffer, Type* str, size_t pos=0, int bytes=0) { for (int i=0; i static void Write(vector& buffer, Type val, size_t pos=0, int bytes=0) { if (bytes == 0) bytes = sizeof(Type); for (int i=0; i>= 8; } } template static void WriteString(vector& buffer, Type* str, size_t pos=0, int bytes=0) { for (int i=0; i>= 8; } } static void WriteString(char* buffer, wchar_t* str, size_t pos=0, int bytes=0) { for (int i=0; i& buffer, wchar_t& retVal, size_t pos=0, int bytes=0) { retVal = wchar_t(0); if (bytes == 0) bytes = SIZEOFWCHAR_T; for (int i=0; i& buffer, wchar_t* str, size_t pos=0, int bytes=0) { for (int i=0; i& buffer, wchar_t val, size_t pos=0, int bytes=0) { if (bytes == 0) bytes = SIZEOFWCHAR_T; for (int i=0; i>= 8; } } static void WriteString(vector& buffer, wchar_t* str, size_t pos=0, int bytes=0) { for (int i=0; i& indices); // Misc functions ULONG GetBlockSize() const {return blockSize_;} void SetBlockSize(ULONG size) { blockSize_ = size; indexEnd_ = fileSize_/blockSize_ + (fileSize_%blockSize_? 1: 0); } protected: vector filename_; ios_base::openmode mode_; fstream file_; ULONG blockSize_; SECT indexEnd_; ULONG fileSize_; }; enum { DUPLICATE_PROPERTY=-6, NAME_TOO_LONG=-5, FILE_NOT_FOUND=-4, DIRECTORY_NOT_EMPTY=-3, DIRECTORY_NOT_FOUND=-2, INVALID_PATH=-1, SUCCESS=1 }; class CompoundFile { public: CompoundFile(); ~CompoundFile(); // User accessible functions public: // Compound File functions bool Create(const wchar_t* filename); bool Open(const wchar_t* filename, ios_base::openmode mode=ios_base::in | ios_base::out); bool Close(); bool IsOpen(); // Directory functions int ChangeDirectory(const wchar_t* path); int MakeDirectory(const wchar_t* path); // File functions int MakeFile(const wchar_t* path); int FileSize(const wchar_t* path, ULONG& size); int ReadFile(const wchar_t* path, char* data); int ReadFile(const wchar_t* path, vector&data); int WriteFile(const wchar_t* path, const char* data, ULONG size); int WriteFile(const wchar_t* path, const vector&data, ULONG size); // ANSI char functions bool Create(const char* filename); bool Open(const char* filename, ios_base::openmode mode=ios_base::in | ios_base::out); int ChangeDirectory(const char* path); int MakeDirectory(const char* path); int MakeFile(const char* path); int FileSize(const char* path, ULONG& size); int ReadFile(const char* path, char* data); int ReadFile(const char* path, vector& data); int WriteFile(const char* path, const char* data, ULONG size); int WriteFile(const char* path, const vector& data, ULONG size); // Protected functions and data members protected: // General functions and data members void IncreaseLocationReferences(vector indices); void DecreaseLocationReferences(vector indices); void SplitPath(const wchar_t* path, wchar_t*& parentpath, wchar_t*& propertyname); vector block_; Block file_; // Header related functions and data members bool LoadHeader(); void SaveHeader(); class Header { public: Header(); void Write(char* block); void Read(char* block); LONGINT _abSig; // 0x0000 Magic number identifying this as a compound file system CLSID _clid; // 0x0008 class id (set with WriteClassStgm retrieved with GetClassFile/ReadClassStg) USHORT _ulMinorVersion; // 0x0018 minor version of the format: 33 is written by reference implementation USHORT _uDllVersion; // 0x001A major version of the dll/format: 3 is written by reference implementation USHORT _uByteOrder; // 0x001C 0xFFFE: indicates Intel byte ordering USHORT _uSectorShift; // 0x001E size of sectors in power-of-two, typically 9, indicating 512-byte sectors USHORT _uMiniSectorShift; // 0x0020 size of mini-sectors in power-of-two, typically 67, indicating 64-byte mini-sectors USHORT _usReserved; // 0x0022 reserved, must be zero ULONG _ulReserved1; // 0x0024 reserved, must be zero ULONG _ulReserved2; // 0x0028 reserved, must be zero FSINDEX _csectFat; // 0x002C number of SECTs in the FAT chain / "Number of elements in the BAT array" SECT _sectDirStat; // 0x0030 first SECT in the directory chain / "Block index of the first block of the property table" DFSIGNATURE _signature; // 0x0034 signature used for transactioning: must be zero, not supported by reference implementation ULONG _ulMiniSectorCutOff;// 0x0038 maximum size for mini-streams: typically 4096 bytes SECT _sectMiniFatStart; // 0x003C first SECT in the mini-FAT chain / "Block index of first big block containing the small block allocation table (SBAT)" FSINDEX _csectMiniFat; // 0x0040 number of SECTs in the mini-FAT chain / "Number of big blocks holding the SBAT" SECT _sectDifStart; // 0x0044 first SECT in the DIFG chain / "Block index of the first block in the Extended Block Allocation Table (XBAT)" FSINDEX _csectDif; // 0x0048 number of SECTs in the DIF chain / "Number of elements in the Extended Block Allocation Table (to be added to the BAT)" SECT _sectFat[109]; // 0x004C..0x01FF the SECTs of the first 109 FAT sectors / "Array of block indices constituting the Block Allocation Table (BAT)" ULONG bigBlockSize_; ULONG smallBlockSize_; private: void Initialize(); }; Header header_; // BAT related functions and data members void LoadBAT(); void SaveBAT(); ULONG DataSize(SECT startIndex, bool isBig); ULONG ReadData(SECT startIndex, char* data, bool isBig); SECT WriteData(const char* data, ULONG size, SECT startIndex, bool isBig); void GetBlockIndices(SECT startIndex, vector& indices, bool isBig); SECT GetFreeBlockIndex(bool isBig); void ExpandBATArray(bool isBig); void LinkBlocks(SECT from, SECT to, bool isBig); void FreeBlocks(vector& indices, bool isBig); vector blocksIndices_; vector sblocksIndices_; // Properties related functions and data members class DirectoryEntry // struct StructuredStorageDirectoryEntry { public: DirectoryEntry(); void Write(char* block); void Read(char* block); friend bool operator==(const COMPOUNDFILE DirectoryEntry& lhs, const COMPOUNDFILE DirectoryEntry& rhs) { return (!wcscmp(lhs.name_, rhs.name_)); } friend bool operator< (const COMPOUNDFILE DirectoryEntry& lhs, const COMPOUNDFILE DirectoryEntry& rhs) { size_t maxLen1 = wcslen(lhs.name_); size_t maxLen2 = wcslen(rhs.name_); if (maxLen1 < maxLen2) return true; else if (maxLen1 > maxLen2) return false; else { int result = wcscmp(lhs.name_, rhs.name_); if (result <= 0) return true; else return false; } } friend bool operator!=(const COMPOUNDFILE DirectoryEntry& lhs, const COMPOUNDFILE DirectoryEntry& rhs) {return !(lhs == rhs);} friend bool operator> (const COMPOUNDFILE DirectoryEntry& lhs, const COMPOUNDFILE DirectoryEntry& rhs) {return (rhs < lhs);} friend bool operator<=(const COMPOUNDFILE DirectoryEntry& lhs, const COMPOUNDFILE DirectoryEntry& rhs) {return !(rhs < lhs);} friend bool operator>=(const COMPOUNDFILE DirectoryEntry& lhs, const COMPOUNDFILE DirectoryEntry& rhs) {return !(lhs < rhs);} wchar_t name_[32]; // 0x00..0x3E the element name in Unicode, padded with zeros to fill the array / "A unicode null-terminated uncompressed 16bit string (lblocke the high bytes) containing the name of the property" WORD _cb_namesize; // 0x40 length of the element name in characters, not bytes / "Number of characters in the NAME field" BYTE _mse; // 0x42 type of object: value taken from the STGTY enumeration / "DirectoryEntry type (directory, file, or root) Byte 1 (directory), 2 (file), or 5 (root entry)" BYTE _bflags; // 0x43 value taken form DECOLOR enumeration / "Node color" CBF_SID _sidLeftSib; // 0x44 SID of the left-sibling of this entry in the directory tree / "Previous property index" CBF_SID _sidRightSib; // 0x48 SID of the right-sibling of this entry in the directroy tree / "Next property index" CBF_SID _sidChild; // 0x4C SID of the child acting as the root of all the children of this element (if _mse=STGTY_STORAGE) / "First child property index" GUID _clsId; // 0x50 CLSID if this storage (if _mse=STGTY_STORAGE) DWORD _dwUserFlags; // 0x60 user flags of this storage (if _mse=STGTY_STORAGE) TIME_T _time[2]; // 0x64 create/modify time stamps (if _mse=STGTY_STORAGE) SECT _sectStart; // 0x74 starting SECT of the stream (if _mse=STGTY_STORAGE) / "Starting block of the file, used as the first block in the file and the pointer to the next block from the BAT" ULONG _ulSize; // 0x78 size of stream in bytes (if _mse=STGTY_STORAGE) / "Actual size of the file this property points to. (used to truncate the blocks to the real size)." DFPROPTYPE _dptPropType; // 0x7C reserved for future use, must be zero }; class PropertyTree { public: PropertyTree(); ~PropertyTree(); PropertyTree* parent_; DirectoryEntry* self_; SECT index_; vector children_; }; void LoadProperties(); void SaveProperties(); int MakeProperty(const wchar_t* path, DirectoryEntry* property); PropertyTree* FindProperty(SECT index); PropertyTree* FindProperty(const wchar_t* path); PropertyTree* FindProperty(PropertyTree* parentTree, wchar_t* name); void InsertPropertyTree(PropertyTree* parentTree, DirectoryEntry* property, SECT index); void DeletePropertyTree(PropertyTree* tree); void UpdateChildrenIndices(PropertyTree* parentTree); void IncreasePropertyReferences(PropertyTree* parentTree, SECT index); void DecreasePropertyReferences(PropertyTree* parentTree, SECT index); PropertyTree* propertyTrees_; PropertyTree* currentDirectory_; vector dirEntries_; vector previousDirectories_; }; #endif // _WIN32 } // namespace YCompoundFiles // reference counting to implement smart pointers namespace RefCount { // reference counter for SmartPtr managed objects struct RefCnt { // On construction the reference counter is initialized with an usage count of 0. RefCnt() : _ref_cnt(0) { } int _ref_cnt; }; // reference counting smart pointer template struct SmartPtr { // default constructor SmartPtr() : _ptr(NULL) { } // The initialized SmartPtr constructor increments the reference counter in struct RefCnt. SmartPtr(T* p) : _ptr(p) { if (p) ++_ptr->_ref_cnt; } // The copy constructor increments the reference counter. SmartPtr(const SmartPtr& other) : _ptr(other._ptr) { if (_ptr) ++_ptr->_ref_cnt; } // The destructor decreases the reference counter and // frees the managed memory as the counter reaches zero. ~SmartPtr() { if (_ptr) { if (!--_ptr->_ref_cnt) delete _ptr; } } // The assignment operator increments the reference counter. SmartPtr& operator=(T* p) { if (_ptr) { if (!--_ptr->_ref_cnt) delete _ptr; _ptr = NULL; } if (p) { _ptr = p; ++_ptr->_ref_cnt; } return *this; } // operator bool() to check for non-empty smart pointers operator bool() const {return _ptr != NULL;} // operator!() to check for empty smart pointers bool operator!() const {return !_ptr;} // operator->() to access the managed objects T* operator->() {return _ptr;} const T* operator->() const {return _ptr;} // Derefence pointed memory T& operator*() {return *_ptr;} const T& operator*() const {return *_ptr;} private: T* _ptr; }; } // namespace RefCount //MF namespace ExcelFormat { struct CellFormat; } namespace YExcel { using namespace YCompoundFiles; #ifdef _WIN32 using namespace WinCompFiles; #endif struct CODE { enum { FORMULA=0x0006, //Token array and the result of a formula cell. YEOF=0x000A, //End of a record block with leading BOF record. CALCCOUNT=0x000C, //Maximum number of times the forumlas should be iteratively calculated CALCMODE=0x000D, //Calculate formulas manually, automatically, or automatically except for multiple table operations PRECISION=0x000E, //Whether formulas use the real cell values for calculation or the values displayed on the screen. REFMODE=0x000F, //Method used to show cell addresses in formulas. DELTA=0x0010, //Maximum change of the result to exit an iteration. ITERATION=0x0011, //Whether iterations are allowed while calculating recursive formulas. PROTECT=0x0012, //Whether worksheet or a workbook is protected against modification. PASSWORD=0x0013, //16-bit hash value, calculated from the worksheet or workbook protection password. HEADER=0x0014, //Page header string for the current worksheet. FOOTER=0x0015, //Page footer string for the current worksheet. EXTERNSHEET=0x0017, //List with indexes to SUPBOOK records NAME=0x0018, //Name and token array of an internal defined name. WINDOWPROTECT=0x0019, //Whether the window configuration of the document is protected. SELECTION=0x001D, //Addresses of all selected cell ranges and position of the active cell for a pane in the current sheet. DATEMODE=0x0022, //Base date for displaying date values. EXTERNNAME=0x0023, //Name of an external defined name, name of an add-in function, a DDE item or an OLE object storage identifier. LEFTMARGIN=0x0026, //Left page margin of the current worksheet. RIGHTMARGIN=0x0027, //Right page margin of the current worksheet. TOPMARGIN=0x0028, //Top page margin of the current worksheet. BOTTOMMARGIN=0x0029, //Bottom page margin of current worksheet PRINTHEADERS=0x002A, //Whether row and column headers (the areas with row numbers and column letters) will be printed. PRINTGRIDLINES=0x002B, //Whether sheet grid lines will be printed. FILEPASS=0x002F, //Information about the read/write password of the file. FONT=0x0031, //Information about a used font, including character formatting. TABLE=0x0036, //Information about a multiple operation table in the sheet. CONTINUE=0x003C, //Continue from previous record WINDOW1=0x003D, //General settings for the workbook global settings. BACKUP=0x0040, //Make backup of file while saving? PANE=0x0041, //Position of window panes. CODEPAGE=0x0042, //Text encoding used to encode byte strings DCONREF=0x0051, DEFCOLWIDTH=0x0055, //Default column width for columns that do not have a specific width set XCT=0x0059, //Number of immediately following CRN records. CRN=0x005A, //Contents of an external cell or cell range. FILESHARING=0x005B, //Information about write protection, for instance the write protection password. WRITEACCESS=0x005C, //Name of the user that has saved the file. UNCALCED=0x005E, //Formulas have not been recalculated before the document was saved. SAVERECALC=0x005F, //"Recalculate before save" option OBJECTPROTECT=0x0063, //Whether objects of the current sheet are protected. COLINFO=0x007D, //Width for a given range of columns GUTS=0x0080, //Layout of outline symbols. WSBOOL=0x0081, //16-bit value with boolean options for the current sheet. GRIDSET=0x0082, //Whether option to print sheet grid lines has ever been changed. HCENTER=0x0083, //Sheet is centred horizontally when printed. VCENTER=0x0084, //Whether sheet is centred vertically when printed. BOUNDSHEET=0x0085, //Sheet inside of the workbook WRITEPROT=0x0086, //Whether file is write protected. COUNTRY=0x008C, //User interface language of the Excel version that has saved the file, system regional settings at the time the file was saved. HIDEOBJ=0x008D, //Whether and how to show objects in the workbook. SORT=0x0090, //Last settings from the "Sort" dialogue for each sheet. PALETTE=0x0092, //Definition of all user-defined colours available for cell and object formatting. SETUP=0x00A1, //Page format settings of the current sheet. SHRFMLA=0x00BC, //Token array of a shared formula. MULRK=0x00BD, //Cell range containing RK value cells. All cells are located in the same row. MULBLANK=0x00BE, //Cell range of empty cells. All cells are located in the same row. DBCELL=0x00D7, //Relative offsets to calculate stream position of the first cell record for each row. BOOKBOOL=0x00DA, //Save values linked from external workbooks records and XCT records? SCENPROTECT=0x00DD, //Whether scenarios of the current sheet are protected. XF=0x00E0, //Formatting information for cells, rows, columns or styles. MERGECELLS=0x00E5, //All merged cell ranges of the current sheet. SST=0x00FC, //List of all strings used anywhere in the workbook. LABELSST=0x00FD, //Cell that contains a string. EXTSST=0x00FF, //Create a hash table with stream offsets to the SST record to optimise string search operations. LABELRANGES=0x015F, //Addresses of all row and column label ranges in the current sheet. USESELFS=0x0160, //Whether formulas in the workbook can use "natural language formulas". DSF=0x0161, //Whether file contains an addition BIFF5/BIFF7 workbook stream. SUPBOOK=0x01AE, //URL of an external document and a list of sheet names inside this document. CONDFMT=0x01B0, //List of cell range addresses for all cells with equal conditional formatting. CF=0x01B1, //Condition and the formatting attributes applied to the cells specified in the CONDFMT record, if the condition is met DVAL=0x01B2, //List header of the data validity table in the current sheet. HLINK=0x01B8, //One cell address or a cell range where all cells contain the same hyperlink. DV=0x01BE, //Data validity settings and a list of cell ranges which contain these settings. DIMENSIONS=0x0200, //Range address of the used area in the current sheet. BLANK=0x0201, //Empty cell, contains cell address and formatting information NUMBER=0x0203, //Cell that contains a floating-point value. BOOLERR=0x0205, //Error value cell STRING=0x0207, //Result of a string formula. ROW=0x0208, //Properties of a single row in the sheet. INDEX=0x020B, //Range of used rows and stream positions of several records of the current sheet. ARRAY=0x0221, //Token array of an array formula WINDOW2=0x023E, //Additional settings for the window of a specific worksheet. RK=0x027E, //Cell that contains an RK value (encoded integer or floating point value). STYLE=0x0293, //Name of a user-defined cell style or specific options for a built-in cell style. FORMAT=0x041E, //Number format. SHRFMLA1=0x04BC, //Token array of a shared formula (added). QUICKTIP=0x0800, //Cell range and text for a tool tip. BOF=0x0809, //Beginning of file SHEETLAYOUT=0x0862, //Colour of the tab below the sheet containing the sheet name. SHEETPROTECTION=0x0867, //Additional options for sheet protection. RANGEPROTECTION=0x0868, //Information about special protected ranges in a protected sheet. SXFORMULA=0x0103, //PivotTable Formula Record }; }; class Record { public: Record(); virtual ~Record(); virtual ULONG Read(const char* data); virtual ULONG Write(char* data); virtual ULONG DataSize(); virtual ULONG RecordSize(); USHORT code_; vector data_; ULONG dataSize_; ULONG recordSize_; vector continueIndices_; }; struct BOF : public Record { BOF(); virtual ULONG Read(const char* data); virtual ULONG Write(char* data); USHORT version_; USHORT type_; USHORT buildIdentifier_; USHORT buildYear_; ULONG fileHistoryFlags_; ULONG lowestExcelVersion_; }; struct YEOF : public Record { YEOF(); }; // String with 1 byte length field struct SmallString { SmallString(); ~SmallString(); SmallString(const SmallString& s); SmallString& operator=(const SmallString& s); const SmallString& operator=(const char* str); const SmallString& operator=(const wchar_t* str); void Reset(); ULONG Read(const char* data); ULONG Write(char* data); ULONG DataSize(); ULONG RecordSize(); ULONG StringSize(); wchar_t* wname_; char* name_; char unicode_; }; // String with 2 byte length field struct LargeString { LargeString(); ~LargeString(); LargeString(const LargeString& s); LargeString& operator=(const LargeString& s); const LargeString& operator=(const char* str); const LargeString& operator=(const wchar_t* str); void Reset(); ULONG Read(const char* data); ULONG ContinueRead(const char* data, int size); ULONG Write(char* data); ULONG DataSize(); ULONG RecordSize(); ULONG StringSize(); vector wname_; vector name_; char unicode_; USHORT richtext_; ULONG phonetic_; }; //MF string conversion functions inline std::string narrow_string(const vector& wstr) { return ::narrow_string(wstring(&*wstr.begin(), wstr.size())); } inline std::wstring widen_string(const vector& wstr) { return ::widen_string(string(&*wstr.begin(), wstr.size())); } inline string stringFromSmallString(const SmallString& ss) { if (ss.unicode_) return ::narrow_string(ss.wname_); else return ss.name_; } inline string stringFromLargeString(const LargeString& ls) { if (ls.unicode_) return narrow_string(ls.wname_); else return string(&*ls.name_.begin(), ls.name_.size()); } inline wstring wstringFromSmallString(const SmallString& ss) { if (ss.unicode_) return ss.wname_; else return ::widen_string(ss.name_); } inline wstring wstringFromLargeString(const LargeString& ls) { if (ls.unicode_) return wstring(&*ls.wname_.begin(), ls.wname_.size()); else return widen_string(ls.name_); } class Workbook { public: Workbook(); public: struct FileProtection; struct CodePage; struct DSF; struct TabID; struct FnGroupCount; struct WorkbookProtection; struct Window1 : public Record { Window1(); virtual ULONG Read(const char* data); virtual ULONG Write(char* data); USHORT horizontalPos_; USHORT verticalPos_; USHORT width_; USHORT height_; USHORT options_; USHORT activeWorksheetIndex_; USHORT firstVisibleTabIndex_; USHORT selectedWorksheetNo_; USHORT worksheetTabBarWidth_; }; struct Backup; struct HideObj; struct DateMode; struct Precision; struct RefreshAll; struct BookBool; struct Font : public Record { Font(); virtual ULONG Read(const char* data); virtual ULONG Write(char* data); virtual ULONG DataSize(); virtual ULONG RecordSize(); USHORT height_; USHORT options_; USHORT colourIndex_; USHORT weight_; USHORT escapementType_; BYTE underlineType_; BYTE family_; BYTE characterSet_; BYTE unused_; SmallString name_; }; struct Format : public Record { //MF Format(); virtual ULONG Read(const char* data); virtual ULONG Write(char* data); virtual ULONG DataSize(); virtual ULONG RecordSize(); USHORT index_; LargeString fmtstring_; }; struct XF : public Record { XF(); virtual ULONG Read(const char* data); virtual ULONG Write(char* data); USHORT fontRecordIndex_; USHORT formatRecordIndex_; USHORT protectionType_; BYTE alignment_; // 0x08: 1 = Text is wrapped at right border BYTE rotation_; BYTE textProperties_; BYTE usedAttributes_; ULONG borderLines_; ULONG colour1_; USHORT colour2_; }; struct Style : public Record { Style(); virtual ULONG Read(const char* data); virtual ULONG Write(char* data); virtual ULONG DataSize(); virtual ULONG RecordSize(); USHORT XFRecordIndex_; BYTE identifier_; BYTE level_; LargeString name_; }; struct Palette; struct UseSelfs; struct BoundSheet : public Record { BoundSheet(); virtual ULONG Read(const char* data); virtual ULONG Write(char* data); virtual ULONG DataSize(); virtual ULONG RecordSize(); ULONG BOFpos_; BYTE visibility_; BYTE type_; SmallString name_; }; struct Country; struct LinkTable; struct SharedStringTable : public Record { SharedStringTable(); virtual ULONG Read(const char* data); virtual ULONG Write(char* data); virtual ULONG DataSize(); virtual ULONG RecordSize(); ULONG stringsTotal_; ULONG uniqueStringsTotal_; vector strings_; }; struct ExtSST : public Record { ExtSST(); virtual ULONG Read(const char* data); virtual ULONG Write(char* data); virtual ULONG DataSize(); virtual ULONG RecordSize(); USHORT stringsTotal_; vector streamPos_; vector firstStringPos_; vector unused_; }; ULONG Read(const char* data); ULONG Write(char* data); ULONG DataSize(); ULONG RecordSize(); BOF bof_; Window1 window1_; vector fonts_; vector XFs_; vector