📄 basicexcelvc6.hpp
字号:
// 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.
#ifndef BASICEXCEL_HPP
#define BASICEXCEL_HPP
#include <algorithm>
#include <cmath>
#include <functional>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <map>
#include <vector>
using namespace std;
#define UTF16
#ifdef UTF16
#define SIZEOFWCHAR_T 2
#else
#define SIZEOFWCHAR_T sizeof(wchar_t)
#endif
namespace YCompoundFiles
{
class Block
// PURPOSE: In charge of handling blocks of data from a file
{
public:
Block();
// File handling 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();
// Block handling functions
bool Read(size_t index, char* block);
bool Write(size_t index, const char* block);
bool Swap(size_t index1, size_t index2);
bool Move(size_t from, size_t to);
bool Insert(size_t index, const char* block);
bool Erase(size_t index);
bool Erase(vector<size_t>& indices);
// Misc functions
size_t GetBlockSize() const {return blockSize_;}
void SetBlockSize(size_t size)
{
blockSize_ = size;
indexEnd_ = fileSize_/blockSize_ + (fileSize_ % blockSize_ ? 1 : 0);
}
protected:
vector<char> filename_;
ios_base::openmode mode_;
fstream file_;
size_t blockSize_;
size_t indexEnd_;
size_t fileSize_;
};
struct LittleEndian
{
#define READWRITE(Type) \
static void Read(const char* buffer, Type& retVal, int pos=0, int bytes=0) \
{ \
retVal = Type(0); \
if (bytes == 0) bytes = sizeof(Type); \
for (size_t i=0; i<bytes; ++i) \
{ \
retVal |= ((Type)((unsigned char)buffer[pos+i])) << 8*i; \
} \
} \
static void ReadString(const char* buffer, Type* str, int pos=0, int bytes=0) \
{ \
for (size_t i=0; i<bytes; ++i) Read(buffer, str[i], pos+i*sizeof(Type)); \
} \
static void Write(char* buffer, Type val, int pos=0, int bytes=0) \
{ \
if (bytes == 0) bytes = sizeof(Type); \
for (size_t i=0; i<bytes; ++i) \
{ \
buffer[pos+i] = (unsigned char)val; \
val >>= 8; \
} \
} \
static void WriteString(char* buffer, Type* str, int pos=0, int bytes=0) \
{ \
for (size_t i=0; i<bytes; ++i) Write(buffer, str[i], pos+i*sizeof(Type)); \
} \
static void Read(const vector<char>& buffer, Type& retVal, int pos=0, int bytes=0) \
{ \
retVal = Type(0); \
if (bytes == 0) bytes = sizeof(Type); \
for (size_t i=0; i<bytes; ++i) \
{ \
retVal |= ((Type)((unsigned char)buffer[pos+i])) << 8*i; \
} \
} \
static void ReadString(const vector<char>& buffer, Type* str, int pos=0, int bytes=0) \
{ \
for (size_t i=0; i<bytes; ++i) Read(buffer, str[i], pos+i*sizeof(Type)); \
} \
static void Write(vector<char>& buffer, Type val, int pos=0, int bytes=0) \
{ \
if (bytes == 0) bytes = sizeof(Type); \
for (size_t i=0; i<bytes; ++i) \
{ \
buffer[pos+i] = (unsigned char)val; \
val >>= 8; \
} \
} \
static void WriteString(vector<char>& buffer, Type* str, int pos=0, int bytes=0) \
{ \
for (size_t i=0; i<bytes; ++i) Write(buffer, str[i], pos+i*sizeof(Type)); \
} \
READWRITE(char)
READWRITE(unsigned char)
READWRITE(short)
READWRITE(int)
READWRITE(unsigned int)
READWRITE(long)
READWRITE(unsigned long)
READWRITE(__int64)
READWRITE(unsigned __int64)
#undef READWRITE
static void Read(const char* buffer, wchar_t& retVal, int pos=0, int bytes=0)
{
retVal = wchar_t(0);
if (bytes == 0) bytes = SIZEOFWCHAR_T;
for (int i=0; i<bytes; ++i)
{
retVal |= ((wchar_t)((unsigned char)buffer[pos+i])) << 8*i;
}
}
static void ReadString(const char* buffer, wchar_t* str, int pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i) Read(buffer, str[i], pos+i*SIZEOFWCHAR_T);
}
static void Write(char* buffer, wchar_t val, int pos=0, int bytes=0)
{
if (bytes == 0) bytes = SIZEOFWCHAR_T;
for (int i=0; i<bytes; ++i)
{
buffer[pos+i] = (unsigned char)val;
val >>= 8;
}
}
static void WriteString(char* buffer, wchar_t* str, int pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i) Write(buffer, str[i], pos+i*SIZEOFWCHAR_T);
}
static void Read(const vector<char>& buffer, wchar_t& retVal, int pos=0, int bytes=0)
{
retVal = wchar_t(0);
if (bytes == 0) bytes = SIZEOFWCHAR_T;
for (int i=0; i<bytes; ++i)
{
retVal |= ((wchar_t)((unsigned char)buffer[pos+i])) << 8*i;
}
}
static void ReadString(const vector<char>& buffer, wchar_t* str, int pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i) Read(buffer, str[i], pos+i*SIZEOFWCHAR_T);
}
static void Write(vector<char>& buffer, wchar_t val, int pos=0, int bytes=0)
{
if (bytes == 0) bytes = SIZEOFWCHAR_T;
for (int i=0; i<bytes; ++i)
{
buffer[pos+i] = (unsigned char)val;
val >>= 8;
}
}
static void WriteString(vector<char>& buffer, wchar_t* str, int pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i) Write(buffer, str[i], pos+i*SIZEOFWCHAR_T);
}
};
class CompoundFile
{
public:
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};
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);
int PresentWorkingDirectory(wchar_t* path);
int PresentWorkingDirectory(vector<wchar_t>& path);
int RemoveDirectory(const wchar_t* path);
int DelTree(const wchar_t* path);
int DirectoryList(vector<vector<wchar_t> >& list, const wchar_t* path=0);
// File functions
int MakeFile(const wchar_t* path);
int RemoveFile(const wchar_t* path);
int FileSize(const wchar_t* path, size_t& size);
int ReadFile(const wchar_t* path, char* data);
int ReadFile(const wchar_t* path, vector<char>&data);
int WriteFile(const wchar_t* path, const char* data, size_t size);
int WriteFile(const wchar_t* path, const vector<char>&data, size_t 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 PresentWorkingDirectory(char* path);
int PresentWorkingDirectory(vector<char>& path);
int RemoveDirectory(const char* path);
int DelTree(const char* path);
int MakeFile(const char* path);
int RemoveFile(const char* path);
int FileSize(const char* path, size_t& size);
int ReadFile(const char* path, char* data);
int ReadFile(const char* path, vector<char>& data);
int WriteFile(const char* path, char* data, size_t size);
int WriteFile(const char* path, vector<char>& data, size_t size);
// Protected functions and data members
protected:
// General functions and data members
void IncreaseLocationReferences(vector<size_t> indices);
void DecreaseLocationReferences(vector<size_t> indices);
void SplitPath(const wchar_t* path, wchar_t*& parentpath, wchar_t*& propertyname);
vector<char> 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);
__int64 fileType_; // Magic number identifying this as a compound file system (0x0000)
int uk1_; // Unknown constant (0x0008)
int uk2_; // Unknown constant (0x000C)
int uk3_; // Unknown constant (0x0010)
int uk4_; // Unknown constant (0x0014)
short uk5_; // Unknown constant (revision?) (0x0018)
short uk6_; // Unknown constant (version?) (0x001A)
short uk7_; // Unknown constant (0x001C)
short log2BigBlockSize_; // Log, base 2, of the big block size (0x001E)
int log2SmallBlockSize_; // Log, base 2, of the small block size (0x0020)
int uk8_; // Unknown constant (0x0024)
int uk9_; // Unknown constant (0x0028)
int BATCount_; // Number of elements in the BAT array (0x002C)
int propertiesStart_; // Block index of the first block of the property table (0x0030)
int uk10_; // Unknown constant (0x0034)
int uk11_; // Unknown constant (0x0038)
int SBATStart_; // Block index of first big block containing the small block allocation table (SBAT) (0x003C)
int SBATCount_; // Number of big blocks holding the SBAT (0x0040)
int XBATStart_; // Block index of the first block in the Extended Block Allocation Table (XBAT) (0x0044)
int XBATCount_; // Number of elements in the Extended Block Allocation Table (to be added to the BAT) (0x0048)
int BATArray_[109]; // Array of block indices constituting the Block Allocation Table (BAT) (0x004C, 0x0050, 0x0054 ... 0x01FC)
size_t bigBlockSize_;
size_t smallBlockSize_;
private:
void Initialize();
};
Header header_;
// BAT related functions and data members
void LoadBAT();
void SaveBAT();
size_t DataSize(size_t startIndex, bool isBig);
size_t ReadData(size_t startIndex, char* data, bool isBig);
size_t WriteData(const char* data, size_t size, int startIndex, bool isBig);
void GetBlockIndices(size_t startIndex, vector<size_t>& indices, bool isBig);
size_t GetFreeBlockIndex(bool isBig);
void ExpandBATArray(bool isBig);
void LinkBlocks(size_t from, size_t to, bool isBig);
void FreeBlocks(vector<size_t>& indices, bool isBig);
vector<int> blocksIndices_;
vector<int> sblocksIndices_;
// Properties related functions and data members
class Property
{
public:
Property();
void Write(char* block);
void Read(char* block);
friend bool operator==(const Property& lhs, const Property& rhs)
{
return (!wcscmp(lhs.name_, rhs.name_));
}
friend bool operator< (const Property& lhs, const Property& 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 Property& lhs, const Property& rhs) {return !(lhs == rhs);}
friend bool operator> (const Property& lhs, const Property& rhs) {return (rhs < lhs);}
friend bool operator<=(const Property& lhs, const Property& rhs) {return !(rhs < lhs);}
friend bool operator>=(const Property& lhs, const Property& rhs) {return !(lhs < rhs);}
wchar_t name_[32]; // A unicode null-terminated uncompressed 16bit string (lblocke the high bytes) containing the name of the property. (0x00, 0x02, 0x04, ... 0x3E)
short nameSize_; // Number of characters in the NAME field (0x40)
unsigned char propertyType_; // Property type (directory, file, or root) Byte 1 (directory), 2 (file), or 5 (root entry) (0x42)
unsigned char nodeColor_; // Node color (0x43)
int previousProp_; // Previous property index (0x44)
int nextProp_; // Next property index (0x48)
int childProp_; // First child property index (0x4c)
int uk1_;
int uk2_;
int uk3_;
int uk4_;
int uk5_;
int seconds1_; // Seconds component of the created timestamp? (0x64)
int days1_; // Days component of the created timestamp? (0x68)
int seconds2_; // Seconds component of the modified timestamp? (0x6C)
int days2_; // Days component of the modified timestamp? (0x70)
int startBlock_; // Starting block of the file, used as the first block in the file and the pointer to the next block from the BAT (0x74)
int size_; // Actual size of the file this property points to. (used to truncate the blocks to the real size). (0x78)
};
class PropertyTree
{
public:
PropertyTree();
~PropertyTree();
PropertyTree* parent_;
Property* self_;
size_t index_;
vector<PropertyTree*> children_;
};
void LoadProperties();
void SaveProperties();
int MakeProperty(const wchar_t* path, Property* property);
PropertyTree* FindProperty(size_t index);
PropertyTree* FindProperty(const wchar_t* path);
PropertyTree* FindProperty(PropertyTree* parentTree, wchar_t* name);
void InsertPropertyTree(PropertyTree* parentTree, Property* property, size_t index);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -