├── .gitignore ├── LuaMiniExcel.def ├── 1.xlsx ├── .gitmodules ├── README.md ├── test.lua ├── test.cpp ├── MiniExcelReader.h ├── CMakeLists.txt ├── LuaMiniExcel.cpp └── MiniExcelReader.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /*.txt 3 | 4 | ~* -------------------------------------------------------------------------------- /LuaMiniExcel.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | luaopen_miniexcel 3 | -------------------------------------------------------------------------------- /1.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qcdong2016/MiniExcel/HEAD/1.xlsx -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tinyxml2"] 2 | path = tinyxml2 3 | url = https://github.com/leethomason/tinyxml2.git 4 | [submodule "minizip"] 5 | path = minizip 6 | url = https://github.com/nmoinvaz/minizip.git 7 | [submodule "zlib"] 8 | path = zlib 9 | url = https://github.com/madler/zlib.git 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MiniExcel 2 | 3 | Mini Excel Reader(just .xlsx) for C++ & Lua 4 | license MIT 5 | 6 | ##Build 7 | * install cmake 2.6+ and make sure cmake in PATH 8 | * run 9 | * `mkdir build & cd build` 10 | * `cmake ..` or `cmake .. -DBUILD_LUA=1` 11 | * `cmake --build .` 12 | 13 | 14 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | local miniexcel = require "miniexcel" 2 | 3 | local x = miniexcel.open('1.xlsx') 4 | 5 | local sheets = x:sheets() 6 | 7 | print(type(sheets), #sheets) 8 | 9 | for i, sheet1 in ipairs(sheets) do 10 | 11 | local f = io.open(sheet1:name() .. '.txt', 'w') 12 | print(sheet1:name()) 13 | 14 | local dim = sheet1:dimension(); 15 | 16 | for r = dim.firstRow, dim.lastRow do 17 | local rowTable = {} 18 | for c = dim.firstCol, dim.lastCol do 19 | local cell = sheet1:cell(r, c) 20 | 21 | local str = "." 22 | if cell then 23 | str = cell.value 24 | end 25 | 26 | table.insert(rowTable, string.format("%30s", str)) 27 | end 28 | f:write(table.concat(rowTable, '|') .. '\n') 29 | end 30 | 31 | f:close() 32 | end 33 | 34 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #include "MiniExcelReader.h" 2 | 3 | int main(int argc, const char *argv[]) 4 | { 5 | MiniExcelReader::ExcelFile x; 6 | if (!x.open("../1.xlsx")) 7 | { 8 | printf("can't open."); 9 | return 1; 10 | } 11 | 12 | MiniExcelReader::Sheet* sh = x.getSheet("Sheet1"); 13 | 14 | FILE* file = fopen("../out.txt", "w"); 15 | 16 | const MiniExcelReader::Range& dim = sh->getDimension(); 17 | 18 | for (int r = dim.firstRow; r <= dim.lastRow; r++) 19 | { 20 | for (int c = dim.firstCol; c <= dim.lastCol; c++) 21 | { 22 | MiniExcelReader::Cell* cell = sh->getCell(r, c); 23 | 24 | const char* str = cell ? cell->value.c_str() : "."; 25 | 26 | fwrite(str, strlen(str), 1, file); 27 | fwrite("|", 1, 1, file); 28 | } 29 | fwrite("\n", 1, 1, file); 30 | } 31 | 32 | fclose(file); 33 | return 0; 34 | } -------------------------------------------------------------------------------- /MiniExcelReader.h: -------------------------------------------------------------------------------- 1 | #ifndef _TINYXLSX_H_ 2 | #define _TINYXLSX_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace MiniExcelReader 8 | { 9 | struct Cell 10 | { 11 | std::string value; 12 | std::string type; 13 | }; 14 | 15 | struct Range 16 | { 17 | int firstRow; 18 | int lastRow; 19 | int firstCol; 20 | int lastCol; 21 | }; 22 | 23 | class Sheet 24 | { 25 | public: 26 | ~Sheet(); 27 | 28 | bool visible() { return _visible; } 29 | const std::string& getName() { return _name; } 30 | Range& getDimension() { return _dimension; } 31 | 32 | Cell* getCell(int row, int col); 33 | private: 34 | friend class ExcelFile; 35 | 36 | int toIndex(int row, int col); 37 | 38 | int _sheetId; 39 | bool _visible; 40 | Range _dimension; 41 | 42 | std::string _rid; 43 | std::string _path; 44 | std::string _name; 45 | 46 | std::vector _cells; 47 | }; 48 | 49 | class Zip; 50 | 51 | class ExcelFile 52 | { 53 | public: 54 | ~ExcelFile(); 55 | bool open(const char* filename); 56 | 57 | Sheet* getSheet(const char* name); 58 | std::vector& sheets() { return _sheets; } 59 | 60 | private: 61 | 62 | void readWorkBook(const char* filename); 63 | void readWorkBookRels(const char* filename); 64 | void readSharedStrings(const char* filename); 65 | void readStyles(const char* filename); 66 | void readSheet(Sheet& sh); 67 | 68 | void parseCell(const std::string& value, int& row, int& col); 69 | void parseRange(const std::string& value, Range& range); 70 | 71 | std::vector _sharedString; 72 | std::vector _sheets; 73 | Zip* _zip; 74 | }; 75 | } 76 | 77 | 78 | #endif -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | project (MiniExcel) 4 | 5 | 6 | set(tinyxml2_src 7 | tinyxml2/tinyxml2.cpp 8 | ) 9 | 10 | set(minizip_src 11 | minizip/ioapi.c 12 | minizip/ioapi_mem.c 13 | minizip/unzip.c 14 | ) 15 | 16 | 17 | set(zlib_src 18 | zlib/adler32.c 19 | zlib/compress.c 20 | zlib/crc32.c 21 | zlib/deflate.c 22 | zlib/gzclose.c 23 | zlib/gzlib.c 24 | zlib/gzread.c 25 | zlib/gzwrite.c 26 | zlib/inflate.c 27 | zlib/infback.c 28 | zlib/inftrees.c 29 | zlib/inffast.c 30 | zlib/trees.c 31 | zlib/uncompr.c 32 | zlib/zutil.c 33 | ) 34 | 35 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 36 | 37 | set(MiniExcel_src MiniExcelReader.cpp) 38 | set(MiniExcelLua_src LuaMiniExcel.cpp LuaMiniExcel.def) 39 | 40 | set(libs tinyxml2 zlib minizip) 41 | 42 | foreach(lib ${libs}) 43 | foreach(src_file ${${lib}_src}) 44 | set(${src_file} ) 45 | get_filename_component (PATH ${src_file} PATH) 46 | string (REPLACE ${CMAKE_CURRENT_SOURCE_DIR} "" PATH ${PATH}) 47 | string (REPLACE / \\ PATH ${PATH}) 48 | source_group ("Source Files\\${PATH}" FILES ${src_file}) 49 | endforeach() 50 | 51 | list(APPEND libsrc ${${lib}_src}) 52 | endforeach() 53 | 54 | include_directories(${libs}) 55 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 56 | 57 | add_executable(MiniExcelTest test.cpp ${MiniExcel_src} ${libsrc}) 58 | 59 | if (BUILD_LUA) 60 | find_package(Lua51 REQUIRED) 61 | include_directories(${LUA_INCLUDE_DIR} ${libs}) 62 | add_library(miniexcel SHARED ${MiniExcel_src} ${MiniExcelLua_src} ${libsrc}) 63 | target_link_libraries(miniexcel ${LUA_LIBRARIES}) 64 | 65 | if (APPLE) 66 | set_property(TARGET miniexcel PROPERTY PREFIX "") 67 | set_property(TARGET miniexcel PROPERTY OUTPUT_NAME "miniexcel.so") 68 | set_property(TARGET miniexcel PROPERTY SUFFIX "") 69 | set_property(TARGET miniexcel PROPERTY SOVERSION "32.1.2.0") 70 | endif() 71 | endif() 72 | -------------------------------------------------------------------------------- /LuaMiniExcel.cpp: -------------------------------------------------------------------------------- 1 | 2 | extern "C" 3 | { 4 | #include "lua.h" 5 | #include "lualib.h" 6 | #include "lauxlib.h" 7 | } 8 | 9 | #include "MiniExcelReader.h" 10 | 11 | using namespace MiniExcelReader; 12 | 13 | template 14 | static void newUserData(lua_State* L, T* p, const char* type) 15 | { 16 | T** ret = (T**)lua_newuserdata(L, sizeof(T*)); 17 | luaL_getmetatable(L, type); 18 | lua_setmetatable(L, -2); 19 | 20 | *ret = p; 21 | } 22 | 23 | template 24 | static T* to(lua_State* L, int n, const char* type) 25 | { 26 | return *(T**)luaL_checkudata(L, n, type); 27 | } 28 | 29 | #define MINI_EXCEL_CELL "Cell" 30 | #define MINI_EXCEL_RANGE "Range" 31 | #define MINI_EXCEL_SHEET "Sheet" 32 | #define MINI_EXCEL_EXCELFILE "ExcelFile" 33 | 34 | #define toExcel(L, n) to(L, n, MINI_EXCEL_EXCELFILE) 35 | #define toSheet(L, n) to(L, n, MINI_EXCEL_SHEET) 36 | #define toRange(L, n) to(L, n, MINI_EXCEL_RANGE) 37 | #define toCell(L, n) to(L, n, MINI_EXCEL_CELL) 38 | 39 | #define newExcel(L, p) newUserData(L, p, MINI_EXCEL_EXCELFILE) 40 | #define newSheet(L, p) newUserData(L, p, MINI_EXCEL_SHEET) 41 | #define newRange(L, p) newUserData(L, p, MINI_EXCEL_RANGE) 42 | #define newCell(L, p) newUserData(L, p, MINI_EXCEL_CELL) 43 | 44 | static int l_open_excel(lua_State* L) 45 | { 46 | const char* file = luaL_checkstring(L, 1); 47 | 48 | ExcelFile* e = new ExcelFile; 49 | 50 | if (!e->open(file)) 51 | { 52 | delete e; 53 | lua_pushnil(L); 54 | return 1; 55 | } 56 | 57 | newExcel(L, e); 58 | 59 | return 1; 60 | } 61 | 62 | static int l_excel_file_gc(lua_State* L) { 63 | ExcelFile* e = toExcel(L, 1); 64 | 65 | if (e) 66 | delete e; 67 | 68 | return 0; 69 | } 70 | 71 | static int l_getSheet(lua_State* L) 72 | { 73 | ExcelFile* e = toExcel(L, 1); 74 | const char* name = luaL_checkstring(L, 2); 75 | 76 | Sheet* s = e->getSheet(name); 77 | 78 | if (s) 79 | newSheet(L, s); 80 | else 81 | lua_pushnil(L); 82 | 83 | return 1; 84 | } 85 | 86 | static int l_sheets(lua_State* L) 87 | { 88 | ExcelFile* e = toExcel(L, 1); 89 | 90 | lua_createtable(L, 0, 0); 91 | 92 | auto& sheets = e->sheets(); 93 | for (unsigned i = 0; i < sheets.size(); i++) 94 | { 95 | Sheet* sh = &sheets[i]; 96 | newSheet(L, sh); 97 | lua_rawseti(L, -2, i+1); 98 | } 99 | 100 | return 1; 101 | } 102 | 103 | static int l_visible(lua_State* L) 104 | { 105 | Sheet* s = toSheet(L, 1); 106 | lua_pushboolean(L, !!s->visible()); 107 | return 1; 108 | } 109 | 110 | static int l_name(lua_State* L) 111 | { 112 | Sheet* s = toSheet(L, 1); 113 | lua_pushstring(L, s->getName().c_str()); 114 | return 1; 115 | } 116 | 117 | static int l_dimension(lua_State* L) 118 | { 119 | Sheet* s = toSheet(L, 1); 120 | newRange(L, &s->getDimension()); 121 | return 1; 122 | } 123 | 124 | static int l_cell(lua_State* L) 125 | { 126 | Sheet* s = toSheet(L, 1); 127 | int row = luaL_checkinteger(L, 2); 128 | int col = luaL_checkinteger(L, 3); 129 | 130 | Cell* c = s->getCell(row, col); 131 | 132 | if (c) 133 | newCell(L, c); 134 | else 135 | lua_pushnil(L); 136 | 137 | return 1; 138 | } 139 | 140 | static luaL_Reg Sheet_functions[] = { 141 | { "visible", l_visible}, 142 | { "name", l_name }, 143 | { "dimension", l_dimension }, 144 | { "cell", l_cell }, 145 | 146 | { NULL, NULL } 147 | }; 148 | 149 | static luaL_Reg ExcelFile_functions[] = { 150 | { "getSheet", l_getSheet }, 151 | { "sheets", l_sheets }, 152 | { "__gc", l_excel_file_gc }, 153 | 154 | { NULL, NULL } 155 | }; 156 | 157 | static luaL_Reg mini_excel_functions[] = { 158 | { "open", l_open_excel }, 159 | { NULL, NULL } 160 | }; 161 | 162 | static int cell_func(lua_State* L) 163 | { 164 | Cell* cell = toCell(L, 1); 165 | const char* name = luaL_checkstring(L, 2); 166 | 167 | if (strcmp(name, "value") == 0) 168 | lua_pushstring(L, cell->value.c_str()); 169 | else if (strcmp(name, "type") == 0) 170 | lua_pushstring(L, cell->type.c_str()); 171 | else 172 | lua_pushnil(L); 173 | 174 | return 1; 175 | } 176 | 177 | static int range_func(lua_State* L) 178 | { 179 | Range* range = toRange(L, 1); 180 | const char* name = luaL_checkstring(L, 2); 181 | 182 | if (strcmp(name, "firstRow") == 0) 183 | lua_pushinteger(L, range->firstRow); 184 | else if (strcmp(name, "lastRow") == 0) 185 | lua_pushinteger(L, range->lastRow); 186 | else if (strcmp(name, "firstCol") == 0) 187 | lua_pushinteger(L, range->firstCol); 188 | else if (strcmp(name, "lastCol") == 0) 189 | lua_pushinteger(L, range->lastCol); 190 | else 191 | lua_pushnil(L); 192 | 193 | return 1; 194 | } 195 | 196 | 197 | static void newMetatable1(lua_State *L, const char * name, luaL_Reg *reg) { 198 | luaL_newmetatable(L, name); 199 | luaL_register(L, NULL, reg); 200 | lua_pushvalue(L, -1); 201 | lua_setfield(L, -2, "__index"); 202 | } 203 | 204 | static void newMetatable2(lua_State *L, const char* name, lua_CFunction f) { 205 | luaL_newmetatable(L, name); 206 | lua_pushcfunction(L, f); 207 | lua_setfield(L, -2, "__index"); 208 | } 209 | 210 | static int miniexcel_open(lua_State* L) { 211 | newMetatable2(L, MINI_EXCEL_CELL, cell_func); 212 | newMetatable2(L, MINI_EXCEL_RANGE, range_func); 213 | newMetatable1(L, MINI_EXCEL_SHEET, Sheet_functions); 214 | newMetatable1(L, MINI_EXCEL_EXCELFILE, ExcelFile_functions); 215 | 216 | lua_newtable(L); 217 | luaL_register(L, NULL, mini_excel_functions); 218 | 219 | return 1; 220 | } 221 | 222 | extern "C" 223 | { 224 | LUA_API int luaopen_miniexcel(lua_State *L) { 225 | return miniexcel_open(L); 226 | } 227 | } 228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /MiniExcelReader.cpp: -------------------------------------------------------------------------------- 1 | #include "MiniExcelReader.h" 2 | 3 | #include "unzip.h" 4 | #include "tinyxml2.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef PATH_MAX 13 | #define PATH_MAX 260 14 | #endif 15 | 16 | namespace MiniExcelReader { 17 | 18 | 19 | struct ZipEntryInfo 20 | { 21 | unz_file_pos pos; 22 | uLong uncompressed_size; 23 | }; 24 | 25 | class Zip 26 | { 27 | public: 28 | ~Zip(); 29 | 30 | bool open(const char* file); 31 | bool openXML(const char* filename, tinyxml2::XMLDocument& doc); 32 | 33 | private: 34 | unsigned char* getFileData(const char* filename, unsigned long& size); 35 | std::map _files; 36 | unzFile _zipFile; 37 | }; 38 | 39 | Zip::~Zip() 40 | { 41 | unzClose(_zipFile); 42 | } 43 | 44 | bool Zip::open(const char* file) 45 | { 46 | _zipFile = unzOpen(file); 47 | 48 | if (!_zipFile) 49 | return false; 50 | 51 | char szCurrentFileName[PATH_MAX]; 52 | unz_file_info64 fileInfo; 53 | 54 | int err = unzGoToNextFile2(_zipFile, &fileInfo, 55 | szCurrentFileName, sizeof(szCurrentFileName) - 1, nullptr, 0, nullptr, 0); 56 | while (err == UNZ_OK) 57 | { 58 | unz_file_pos posInfo; 59 | if (unzGetFilePos(_zipFile, &posInfo) == UNZ_OK) 60 | { 61 | std::string currentFileName = szCurrentFileName; 62 | 63 | ZipEntryInfo entry; 64 | entry.pos = posInfo; 65 | entry.uncompressed_size = (uLong)fileInfo.uncompressed_size; 66 | _files[currentFileName] = entry; 67 | } 68 | err = unzGoToNextFile2(_zipFile, &fileInfo, 69 | szCurrentFileName, sizeof(szCurrentFileName) - 1, nullptr, 0, nullptr, 0); 70 | } 71 | 72 | return true; 73 | } 74 | 75 | unsigned char* Zip::getFileData(const char* filename, unsigned long& size) 76 | { 77 | unsigned char * pBuffer = NULL; 78 | 79 | auto it = _files.find(filename); 80 | 81 | if (it == _files.end()) return NULL; 82 | 83 | ZipEntryInfo fileInfo = it->second; 84 | 85 | int nRet = unzGoToFilePos(_zipFile, &fileInfo.pos); 86 | if (UNZ_OK != nRet) return NULL; 87 | 88 | nRet = unzOpenCurrentFile(_zipFile); 89 | if (UNZ_OK != nRet) return NULL; 90 | 91 | pBuffer = new unsigned char[fileInfo.uncompressed_size]; 92 | unzReadCurrentFile(_zipFile, pBuffer, fileInfo.uncompressed_size); 93 | 94 | size = fileInfo.uncompressed_size; 95 | unzCloseCurrentFile(_zipFile); 96 | 97 | return pBuffer; 98 | } 99 | 100 | bool Zip::openXML(const char* filename, tinyxml2::XMLDocument& doc) 101 | { 102 | unsigned long size = 0; 103 | unsigned char* data = getFileData(filename, size); 104 | 105 | if (!data) return false; 106 | 107 | doc.Parse((const char*)data, size); 108 | 109 | if (data) 110 | delete[] data; 111 | 112 | return true; 113 | } 114 | 115 | 116 | Sheet::~Sheet() 117 | { 118 | for (unsigned i = 0; i < _cells.size(); i++) 119 | { 120 | delete _cells[i]; 121 | } 122 | } 123 | 124 | Cell* Sheet::getCell(int row, int col) 125 | { 126 | if (row < _dimension.firstRow || row > _dimension.lastRow) 127 | return nullptr; 128 | if (col < _dimension.firstCol || col > _dimension.lastCol) 129 | return nullptr; 130 | 131 | return _cells[toIndex(row, col)]; 132 | } 133 | 134 | 135 | int Sheet::toIndex(int row, int col) 136 | { 137 | return (row - 1) * (_dimension.lastCol - _dimension.firstCol + 1) + (col- _dimension.firstCol); 138 | } 139 | 140 | void ExcelFile::readWorkBook(const char* filename) 141 | { 142 | tinyxml2::XMLDocument doc; 143 | 144 | _zip->openXML(filename, doc); 145 | 146 | tinyxml2::XMLElement* e; 147 | e = doc.FirstChildElement("workbook"); 148 | e = e->FirstChildElement("sheets"); 149 | e = e->FirstChildElement("sheet"); 150 | 151 | while (e) 152 | { 153 | Sheet s; 154 | 155 | s._name = e->Attribute("name"); 156 | s._rid = e->Attribute("r:id"); 157 | s._sheetId = e->IntAttribute("sheetId"); 158 | s._visible = (e->Attribute("state") && !strcmp(e->Attribute("state"), "hidden")); 159 | 160 | e = e->NextSiblingElement("sheet"); 161 | 162 | _sheets.push_back(s); 163 | } 164 | } 165 | 166 | void ExcelFile::readWorkBookRels(const char* filename) 167 | { 168 | tinyxml2::XMLDocument doc; 169 | 170 | _zip->openXML(filename, doc); 171 | tinyxml2::XMLElement* e = doc.FirstChildElement("Relationships"); 172 | e = e->FirstChildElement("Relationship"); 173 | 174 | while (e) 175 | { 176 | const char* rid = e->Attribute("Id"); 177 | 178 | for (Sheet& sheet : _sheets) 179 | { 180 | if (sheet._rid == rid) 181 | { 182 | sheet._path = "xl/" + std::string(e->Attribute("Target")); 183 | 184 | break; 185 | } 186 | } 187 | 188 | e = e->NextSiblingElement("Relationship"); 189 | } 190 | } 191 | 192 | void ExcelFile::readSharedStrings(const char* filename) 193 | { 194 | tinyxml2::XMLDocument doc; 195 | 196 | if (!_zip->openXML(filename, doc)) return; 197 | 198 | tinyxml2::XMLElement* e; 199 | 200 | e = doc.FirstChildElement("sst"); 201 | e = e->FirstChildElement("si"); 202 | 203 | tinyxml2::XMLElement *t, *r; 204 | int i = 0; 205 | 206 | while (e) 207 | { 208 | t = e->FirstChildElement("t"); 209 | i++; 210 | if (t) 211 | { 212 | const char* text = t->GetText(); 213 | _sharedString.push_back(text ? text : ""); 214 | } 215 | else 216 | { 217 | r = e->FirstChildElement("r"); 218 | std::string value; 219 | while (r) 220 | { 221 | t = r->FirstChildElement("t"); 222 | value += t->GetText(); 223 | r = r->NextSiblingElement("r"); 224 | } 225 | _sharedString.push_back(value); 226 | } 227 | e = e->NextSiblingElement("si"); 228 | } 229 | } 230 | 231 | void ExcelFile::readStyles(const char* filename) 232 | { 233 | tinyxml2::XMLDocument doc; 234 | 235 | _zip->openXML(filename, doc); 236 | } 237 | 238 | void ExcelFile::parseCell(const std::string& value, int& row, int& col) 239 | { 240 | int index = 0; 241 | col = 0; 242 | 243 | int arr[10]; 244 | 245 | while (index < (int)value.length()) 246 | { 247 | if (isdigit(value[index])) break; 248 | arr[index] = value[index] - 'A' + 1; 249 | index++; 250 | } 251 | 252 | for (int i = 0; i < index; i++) 253 | { 254 | col += (int)(arr[i] * pow(26, index - i - 1)); 255 | } 256 | 257 | row = atoi(value.c_str() + index); 258 | } 259 | 260 | void ExcelFile::parseRange(const std::string& value, Range& range) 261 | { 262 | int index = value.find_first_of(':'); 263 | 264 | if (index != -1) 265 | { 266 | parseCell(value.substr(0, index), range.firstRow, range.firstCol); 267 | parseCell(value.substr(index+1), range.lastRow, range.lastCol); 268 | } 269 | else 270 | { 271 | parseCell(value, range.firstRow, range.firstCol); 272 | range.lastCol = range.firstCol; 273 | range.lastRow = range.firstRow; 274 | } 275 | } 276 | 277 | void ExcelFile::readSheet(Sheet& sh) 278 | { 279 | tinyxml2::XMLDocument doc; 280 | tinyxml2::XMLElement *root, *row, *c, *v, *d; 281 | 282 | _zip->openXML(sh._path.c_str(), doc); 283 | 284 | root = doc.FirstChildElement("worksheet"); 285 | 286 | d = root->FirstChildElement("dimension"); 287 | if (d) 288 | parseRange(d->Attribute("ref"), sh._dimension); 289 | 290 | row = root->FirstChildElement("sheetData"); 291 | row = row->FirstChildElement("row"); 292 | 293 | int vecsize = (sh._dimension.lastCol - sh._dimension.firstCol + 1) * (sh._dimension.lastRow - sh._dimension.firstRow + 1); 294 | 295 | sh._cells.resize(vecsize); 296 | 297 | 298 | while (row) 299 | { 300 | int rowIdx = row->IntAttribute("r"); 301 | c = row->FirstChildElement("c"); 302 | 303 | while (c) 304 | { 305 | int colIdx = 0; 306 | parseCell(c->Attribute("r"), rowIdx, colIdx); 307 | int index = sh.toIndex(rowIdx, colIdx); 308 | 309 | const char *s, *t; 310 | 311 | v = c->FirstChildElement("v"); 312 | t = c->Attribute("t"); 313 | 314 | Cell* cell = new Cell; 315 | 316 | if (v) 317 | { 318 | s = v->GetText(); 319 | if (t && !strcmp(t, "s")) 320 | { 321 | cell->value = _sharedString[atoi(s)]; 322 | cell->type = "string"; 323 | } 324 | else 325 | { 326 | cell->type = "unknow"; 327 | cell->value = s; 328 | } 329 | } 330 | sh._cells[index] = cell; 331 | c = c->NextSiblingElement("c"); 332 | } 333 | 334 | row = row->NextSiblingElement("row"); 335 | } 336 | } 337 | 338 | ExcelFile::~ExcelFile() 339 | { 340 | if (_zip) delete _zip; 341 | } 342 | 343 | bool ExcelFile::open(const char* filename) 344 | { 345 | _zip = new Zip(); 346 | 347 | if (!_zip->open(filename)) 348 | return false; 349 | 350 | readWorkBook("xl/workbook.xml"); 351 | readWorkBookRels("xl/_rels/workbook.xml.rels"); 352 | readSharedStrings("xl/sharedStrings.xml"); 353 | readStyles("styles.xml"); 354 | 355 | for (auto& s : _sheets) 356 | { 357 | readSheet(s); 358 | } 359 | 360 | return true; 361 | } 362 | 363 | 364 | Sheet* ExcelFile::getSheet(const char* name) 365 | { 366 | for (Sheet& sh : _sheets) 367 | { 368 | if (sh._name == name) 369 | return &sh; 370 | } 371 | 372 | return nullptr; 373 | } 374 | 375 | } --------------------------------------------------------------------------------