diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index c2d802a..81bc867 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -18,6 +18,7 @@ set(SAPI_CONTRIB_SANDBOXES hunspell jsonnet libidn2 + libxls libzip pffft turbojpeg diff --git a/contrib/README.md b/contrib/README.md index 7f8060d..d184de2 100644 --- a/contrib/README.md +++ b/contrib/README.md @@ -11,6 +11,7 @@ Directory | Project `hunspell/` | Hunspell - The most popular spellchecking library | [github.com/hunspell/hunspell](https://github.com/hunspell/hunspell) | CMake `jsonnet/` | Jsonnet - The Data Templating Language | [github.com/google/jsonnet](https://github.com/google/jsonnet) | CMake `libidn2/` | libidn2 - GNU IDN library | [www.gnu.org/software/libidn/#libidn2](https://www.gnu.org/software/libidn/#libidn2) | CMake +`libxls/` | libxls- Read binary Excel files from C/C++ | [https://github.com/libxls/libxls](https://github.com/libxls/libxls) | CMake `libzip/` | libzip - operations on zip archives | [github.com/nih-at/libzip](https://github.com/nih-at/libzip) | CMake `pffft/` | PFFFT - a pretty fast Fourier Transform | [bitbucket.org/jpommier/pffft.git](https://bitbucket.org/jpommier/pffft.git) | CMake `turbojpeg/` | High-level JPEG library | [libjpeg-turbo.org/About/TurboJPEG](https://libjpeg-turbo.org/About/TurboJPEG) | CMake diff --git a/contrib/libxls/CMakeLists.txt b/contrib/libxls/CMakeLists.txt new file mode 100644 index 0000000..b5c07f5 --- /dev/null +++ b/contrib/libxls/CMakeLists.txt @@ -0,0 +1,117 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.13..3.22) + +project(sapi_libxls) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree") + +if(NOT TARGET sapi::sapi) + set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree") + add_subdirectory("${SAPI_ROOT}" + "${CMAKE_BINARY_DIR}/sandboxed-api-build" + EXCLUDE_FROM_ALL) +endif() + +FetchContent_Declare(libxls + GIT_REPOSITORY https://github.com/libxls/libxls.git + GIT_TAG 448240067919707eb95fb009f76f3fdb439b1427 +) + +FetchContent_GetProperties(libxls) +if(NOT libxls_POPULATED) + FetchContent_Populate(libxls) + set(libxls_STATUS_FILE "${libxls_SOURCE_DIR}/config.status") + if(EXISTS "${libxls_STATUS_FILE}") + file(SHA256 "${libxls_STATUS_FILE}" _sapi_CONFIG_STATUS) + endif() + if(NOT _sapi_CONFIG_STATUS STREQUAL "${libxls_CONFIG_STATUS}") + message("-- Configuring libxls...") + execute_process( + COMMAND autoreconf -i + WORKING_DIRECTORY "${libxls_SOURCE_DIR}" + RESULT_VARIABLE _sapi_libxls_autoreconf_result + ) + if(NOT _sapi_libxls_autoreconf_result EQUAL "0") + message(FATAL_ERROR "Configuration for libxls failed: " + "${_sapi_libxls_autoreconf_result}") + endif() + execute_process( + COMMAND ./configure --disable-dependency-tracking + WORKING_DIRECTORY "${libxls_SOURCE_DIR}" + RESULT_VARIABLE _sapi_libxls_config_result + ) + if(NOT _sapi_libxls_config_result EQUAL "0") + message(FATAL_ERROR "Configuration for libxls failed: " + "${_sapi_libxls_config_result}") + endif() + file(SHA256 "${libxls_SOURCE_DIR}/config.status" _sapi_CONFIG_STATUS) + set(libxls_CONFIG_STATUS "${_sapi_CONFIG_STATUS}" CACHE INTERNAL "") + endif() +endif() + +add_library(libxls STATIC + "${libxls_SOURCE_DIR}/src/endian.c" + "${libxls_SOURCE_DIR}/src/locale.c" + "${libxls_SOURCE_DIR}/src/ole.c" + "${libxls_SOURCE_DIR}/src/xls.c" + "${libxls_SOURCE_DIR}/src/xlstool.c" +) + +target_include_directories(libxls PUBLIC + "${libxls_SOURCE_DIR}" + "${libxls_SOURCE_DIR}/include" +) + +configure_file(xls.gen.h.in xls.gen.h) + +add_sapi_library( + sapi_libxls + + FUNCTIONS + xls_open_file + + xls_getWorkSheet + xls_parseWorkSheet + + xls_cell + + xls_close_WS + xls_close_WB + + xls_getError + + INPUTS + "${CMAKE_BINARY_DIR}/xls.gen.h" + + LIBRARY libxls + LIBRARY_NAME Libxls + NAMESPACE "" +) +add_library(sapi_contrib::libxls ALIAS sapi_libxls) +target_include_directories(sapi_libxls INTERFACE + "${PROJECT_BINARY_DIR}" +) + +if(SAPI_ENABLE_EXAMPLES) + add_subdirectory(example) +endif() + +if(SAPI_ENABLE_TESTS) + add_subdirectory(test) +endif() diff --git a/contrib/libxls/example/CMakeLists.txt b/contrib/libxls/example/CMakeLists.txt new file mode 100644 index 0000000..3882c39 --- /dev/null +++ b/contrib/libxls/example/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_executable( + sapi_minixls + + main.cc + ../utils/utils_libxls.cc +) + +target_link_libraries( + sapi_minixls PRIVATE + + sapi_libxls + sapi::sapi + absl::flags_parse +) diff --git a/contrib/libxls/example/main.cc b/contrib/libxls/example/main.cc new file mode 100644 index 0000000..c219edc --- /dev/null +++ b/contrib/libxls/example/main.cc @@ -0,0 +1,89 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include +#include +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "contrib/libxls/sandboxed.h" +#include "contrib/libxls/utils/utils_libxls.h" + +ABSL_FLAG(uint32_t, sheet, 0, "sheet number"); + +int main(int argc, char* argv[]) { + std::string prog_name(argv[0]); + google::InitGoogleLogging(argv[0]); + std::vector args = absl::ParseCommandLine(argc, argv); + + if (args.size() != 2) { + std::cerr << "Usage:\n " << prog_name << " INPUT\n"; + return EXIT_FAILURE; + } + + LibxlsSapiSandbox sandbox(args[1]); + if (!sandbox.Init().ok()) { + std::cerr << "Unable to start sandbox\n"; + return EXIT_FAILURE; + } + + absl::StatusOr wb = LibXlsWorkbook::Open(&sandbox, args[1]); + + uint32_t nr_sheet = absl::GetFlag(FLAGS_sheet); + + absl::StatusOr sheet = wb->OpenSheet(nr_sheet); + if (!sheet.ok()) { + std::cerr << "Unable to switch sheet: "; + std::cerr << sheet.status() << "\n"; + return EXIT_FAILURE; + } + + for (size_t row = 0; row < sheet->GetRowCount(); ++row) { + for (size_t col = 0; col < sheet->GetColCount(); ++col) { + absl::StatusOr cell = sheet->GetCell(row, col); + if (!cell.ok()) { + std::cerr << "Unable to get cell: "; + std::cerr << cell.status() << "\n"; + return EXIT_FAILURE; + } + switch (cell->type) { + case XLS_RECORD_NUMBER: + std::cout << std::setw(16) << std::get(cell->value) << " | "; + break; + case XLS_RECORD_STRING: + std::cout << std::setw(16) << std::get(cell->value) + << " | "; + break; + case XLS_RECORD_BOOL: + std::cout << std::setw(16) << std::get(cell->value) << " | "; + break; + case XLS_RECORD_BLANK: + std::cout << std::setw(16) << " | "; + break; + case XLS_RECORD_ERROR: + std::cout << "error" + << "\n"; + break; + } + } + std::cout << "\n"; + } + return EXIT_SUCCESS; +} diff --git a/contrib/libxls/files/t1.xls b/contrib/libxls/files/t1.xls new file mode 100644 index 0000000..ac94180 Binary files /dev/null and b/contrib/libxls/files/t1.xls differ diff --git a/contrib/libxls/files/t2.xls b/contrib/libxls/files/t2.xls new file mode 100644 index 0000000..35f6d66 Binary files /dev/null and b/contrib/libxls/files/t2.xls differ diff --git a/contrib/libxls/files/t3.xls b/contrib/libxls/files/t3.xls new file mode 100644 index 0000000..a14cd64 Binary files /dev/null and b/contrib/libxls/files/t3.xls differ diff --git a/contrib/libxls/sandboxed.h b/contrib/libxls/sandboxed.h new file mode 100644 index 0000000..bdc19bf --- /dev/null +++ b/contrib/libxls/sandboxed.h @@ -0,0 +1,48 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CONTRIB_ZSTD_SANDBOXED_H_ +#define CONTRIB_ZSTD_SANDBOXED_H_ + +#include +#include + +#include + +#include "sapi_libxls.sapi.h" // NOLINT(build/include) + +class LibxlsSapiSandbox : public LibxlsSandbox { + public: + explicit LibxlsSapiSandbox(std::string filename) + : filename_(std::move(filename)) {} + + std::unique_ptr ModifyPolicy( + sandbox2::PolicyBuilder*) override { + return sandbox2::PolicyBuilder() + .AllowDynamicStartup() + .AllowOpen() + .AllowRead() + .AllowWrite() + .AllowSystemMalloc() + .AllowExit() + .AllowSyscall(__NR_recvmsg) + .AddFile(filename_) + .BuildOrDie(); + } + + private: + std::string filename_; +}; + +#endif // CONTRIB_LIBXLS_SANDBOXED_H_ diff --git a/contrib/libxls/test/CMakeLists.txt b/contrib/libxls/test/CMakeLists.txt new file mode 100644 index 0000000..0dc7c98 --- /dev/null +++ b/contrib/libxls/test/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +include(GoogleTest) + +add_executable( + sapi_libxls_test + + libxls_test.cc + ../utils/utils_libxls.cc +) + + +target_link_libraries( + sapi_libxls_test PRIVATE + + sapi_libxls + sapi::test_main + sapi::temp_file +) + +gtest_discover_tests(sapi_libxls_test PROPERTIES ENVIRONMENT "TEST_FILES_DIR=${PROJECT_SOURCE_DIR}/files") diff --git a/contrib/libxls/test/libxls_test.cc b/contrib/libxls/test/libxls_test.cc new file mode 100644 index 0000000..b7afb87 --- /dev/null +++ b/contrib/libxls/test/libxls_test.cc @@ -0,0 +1,143 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "contrib/libxls/sandboxed.h" +#include "contrib/libxls/utils/utils_libxls.h" +#undef FILE // XXX: artefect from genereted header + +#include "sandboxed_api/util/path.h" +#include "sandboxed_api/util/status_matchers.h" + +namespace { + +using ::sapi::IsOk; +using ::testing::Not; + +struct Sheet { + int count_row; + int count_col; + double values[4][4]; +}; + +const struct TestCase { + std::string filename; + size_t sheet_count; + struct Sheet sheet[2]; +} kTestData[] = { + { + .filename = "t1.xls", + .sheet_count = 1, + .sheet = + { + {.count_row = 4, + .count_col = 2, + .values = + { + {1, 2, 0, 0}, + {3, 4, 0, 0}, + {5, 6, 0, 0}, + {7, 8, 0, 0}, + }}, + }, + }, + { + .filename = "t2.xls", + .sheet_count = 2, + .sheet = + { + {.count_row = 2, + .count_col = 3, + .values = + { + {1, 2, 3, 0}, + {4, 5, 6, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }}, + {.count_row = 2, + .count_col = 2, + .values = + { + {9, 8, 0, 0}, + {7, 6, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }}, + }, + }, +}; + +class LibXlsBase : public testing::Test { + protected: + std::string GetTestFilePath(const std::string& filename) { + return sapi::file::JoinPath(test_dir_, filename); + } + + void SetUp() override; + + const char* test_dir_; +}; + +class LibXlsTestFiles : public LibXlsBase, + public testing::WithParamInterface {}; + +void LibXlsBase::SetUp() { + test_dir_ = getenv("TEST_FILES_DIR"); + ASSERT_NE(test_dir_, nullptr); +} + +TEST_P(LibXlsTestFiles, TestValues) { + const TestCase& tv = GetParam(); + std::string test_file_path = GetTestFilePath(tv.filename); + + LibxlsSapiSandbox sandbox(test_file_path); + SAPI_ASSERT_OK(sandbox.Init()); + + SAPI_ASSERT_OK_AND_ASSIGN(LibXlsWorkbook wb, + LibXlsWorkbook::Open(&sandbox, test_file_path)); + ASSERT_EQ(wb.GetSheetCount(), tv.sheet_count); + + for (int i = 0; i < tv.sheet_count; ++i) { + SAPI_ASSERT_OK_AND_ASSIGN(LibXlsSheet sheet, wb.OpenSheet(i)); + ASSERT_EQ(sheet.GetRowCount(), tv.sheet[i].count_row); + ASSERT_EQ(sheet.GetColCount(), tv.sheet[i].count_col); + for (size_t row = 0; row < sheet.GetRowCount(); ++row) { + for (size_t col = 0; col < sheet.GetColCount(); ++col) { + SAPI_ASSERT_OK_AND_ASSIGN(LibXlsCell cell, sheet.GetCell(row, col)); + ASSERT_EQ(cell.type, XLS_RECORD_NUMBER); + ASSERT_EQ(std::get(cell.value), tv.sheet[i].values[row][col]); + } + } + } +} + +INSTANTIATE_TEST_SUITE_P(LibXlsBase, LibXlsTestFiles, + testing::ValuesIn(kTestData)); + +TEST_F(LibXlsBase, TestFormula) { + std::string test_file_path = GetTestFilePath("t3.xls"); + + LibxlsSapiSandbox sandbox(test_file_path); + SAPI_ASSERT_OK(sandbox.Init()); + + SAPI_ASSERT_OK_AND_ASSIGN(LibXlsWorkbook wb, + LibXlsWorkbook::Open(&sandbox, test_file_path)); + + SAPI_ASSERT_OK_AND_ASSIGN(LibXlsSheet sheet, wb.OpenSheet(0)); + SAPI_ASSERT_OK_AND_ASSIGN(LibXlsCell cell, sheet.GetCell(0, 0)); + ASSERT_EQ(cell.type, XLS_RECORD_STRING); + ASSERT_EQ(std::get(cell.value), "10.000000"); +} + +} // namespace diff --git a/contrib/libxls/utils/utils_libxls.cc b/contrib/libxls/utils/utils_libxls.cc new file mode 100644 index 0000000..6efc3c1 --- /dev/null +++ b/contrib/libxls/utils/utils_libxls.cc @@ -0,0 +1,162 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "contrib/libxls/utils/utils_libxls.h" + +#include +#include +#include + +#include "contrib/libxls/sandboxed.h" + +absl::Status GetError(LibxlsApi* api, xls_error_t error_code) { + SAPI_ASSIGN_OR_RETURN(const char* c_errstr, api->xls_getError(error_code)); + sapi::v::RemotePtr sapi_errstr(const_cast(c_errstr)); + SAPI_ASSIGN_OR_RETURN(std::string errstr, + api->GetSandbox()->GetCString(sapi_errstr)); + + return absl::UnavailableError(errstr); +} + +absl::StatusOr LibXlsWorkbook::Open(LibxlsSapiSandbox* sandbox, + const std::string& filename, + const std::string& encode) { + if (sandbox == nullptr) { + return absl::InvalidArgumentError("Sandbox has to be defined"); + } + + LibxlsApi api(sandbox); + + sapi::v::IntBase sapi_error; + sapi::v::CStr sapi_filename(filename.c_str()); + sapi::v::CStr sapi_encode(encode.c_str()); + + SAPI_ASSIGN_OR_RETURN( + xlsWorkBook* wb, + api.xls_open_file(sapi_filename.PtrBefore(), sapi_encode.PtrBefore(), + sapi_error.PtrAfter())); + + if (wb == nullptr) { + return GetError(&api, sapi_error.GetValue()); + } + + sapi::v::Struct sapi_wb; + sapi_wb.SetRemote(wb); + SAPI_RETURN_IF_ERROR(sandbox->TransferFromSandboxee(&sapi_wb)); + + return LibXlsWorkbook(sandbox, wb, sapi_wb.data().sheets.count); +} + +LibXlsWorkbook::~LibXlsWorkbook() { + if (rwb_ != nullptr) { + sapi::v::RemotePtr sapi_rwb(rwb_); + LibxlsApi api(sandbox_); + api.xls_close_WB(&sapi_rwb).IgnoreError(); + } +} + +size_t LibXlsWorkbook::GetSheetCount() { return sheet_count_; } + +absl::StatusOr LibXlsWorkbook::OpenSheet(uint32_t index) { + if (GetSheetCount() <= index) { + return absl::OutOfRangeError("Index out of range"); + } + + LibxlsApi api(sandbox_); + sapi::v::RemotePtr sapi_rwb(rwb_); + SAPI_ASSIGN_OR_RETURN(xlsWorkSheet* ws, + api.xls_getWorkSheet(&sapi_rwb, index)); + if (ws == nullptr) { + return absl::UnavailableError("Unable to open sheet"); + } + + sapi::v::Struct sapi_ws; + sapi_ws.SetRemote(ws); + SAPI_ASSIGN_OR_RETURN(xls_error_t error_code, + api.xls_parseWorkSheet(sapi_ws.PtrAfter())); + if (error_code != 0) { + return GetError(&api, error_code); + } + + return LibXlsSheet(sandbox_, ws, sapi_ws.data().rows.lastrow + 1, + sapi_ws.data().rows.lastcol + 1); +} + +size_t LibXlsSheet::GetRowCount() const { return row_; } + +size_t LibXlsSheet::GetColCount() const { return col_; } + +absl::StatusOr LibXlsSheet::GetStr( + const sapi::v::Struct& sapi_cell) { + if (sapi_cell.data().str == nullptr) { + return ""; + } + + sapi::v::RemotePtr sapi_str(sapi_cell.data().str); + return sandbox_->GetCString(sapi_str); +} + +absl::StatusOr LibXlsSheet::GetNewCell( + const sapi::v::Struct& sapi_cell) { + int id = sapi_cell.data().id; + double d = sapi_cell.data().d; + + switch (id) { + case XLS_RECORD_RK: + case XLS_RECORD_MULRK: + case XLS_RECORD_NUMBER: + return LibXlsCell{XLS_RECORD_NUMBER, d}; + case XLS_RECORD_BLANK: + return LibXlsCell{XLS_RECORD_BLANK, 0.0}; + case XLS_RECORD_FORMULA: + SAPI_ASSIGN_OR_RETURN(std::string cell_str, GetStr(sapi_cell)); + if (cell_str == "bool") { + return LibXlsCell{XLS_RECORD_BOOL, d > 0}; + } else if (cell_str == "error") { + return LibXlsCell{XLS_RECORD_ERROR, cell_str}; + } + return LibXlsCell{XLS_RECORD_STRING, cell_str}; + } + + return absl::UnavailableError("Unknown type"); +} + +absl::StatusOr LibXlsSheet::GetCell(uint32_t row, uint32_t col) { + if (row >= GetRowCount()) { + return absl::OutOfRangeError("Row out of range"); + } + if (col >= GetColCount()) { + return absl::OutOfRangeError("Col out of range"); + } + + LibxlsApi api(sandbox_); + sapi::v::RemotePtr sapi_rws(rws_); + SAPI_ASSIGN_OR_RETURN(xlsCell* cell, api.xls_cell(&sapi_rws, row, col)); + if (cell == nullptr) { + return absl::UnavailableError("Unable to get cell"); + } + sapi::v::Struct sapi_cell; + sapi_cell.SetRemote(cell); + SAPI_RETURN_IF_ERROR(sandbox_->TransferFromSandboxee(&sapi_cell)); + + return GetNewCell(sapi_cell); +} + +LibXlsSheet::~LibXlsSheet() { + if (rws_ != nullptr) { + LibxlsApi api(sandbox_); + sapi::v::RemotePtr sapi_rws(rws_); + api.xls_close_WS(&sapi_rws).IgnoreError(); + } +} diff --git a/contrib/libxls/utils/utils_libxls.h b/contrib/libxls/utils/utils_libxls.h new file mode 100644 index 0000000..6b0d77f --- /dev/null +++ b/contrib/libxls/utils/utils_libxls.h @@ -0,0 +1,106 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CONTRIB_LIBPCAP_UTILS_UTILS_LIBPCAP_H_ +#define CONTRIB_LIBPCAP_UTILS_UTILS_LIBPCAP_H_ + +#include + +#include "contrib/libxls/sandboxed.h" + +#define XLS_RECORD_FORMULA 0x0006 +#define XLS_RECORD_MULRK 0x00BD +#define XLS_RECORD_BLANK 0x0201 +#define XLS_RECORD_NUMBER 0x0203 +#define XLS_RECORD_STRING 0x0207 +#define XLS_RECORD_RK 0x027E +#define XLS_RECORD_BOOL 0x9998 +#define XLS_RECORD_ERROR 0x9999 + +struct LibXlsCell { + int type; + std::variant value; +}; + +class LibXlsSheet { + friend class LibXlsWorkbook; + + public: + size_t GetRowCount() const; + size_t GetColCount() const; + absl::StatusOr GetCell(uint32_t row, uint32_t col); + + ~LibXlsSheet(); + + LibXlsSheet(LibXlsSheet&& other) { *this = std::move(other); } + + LibXlsSheet& operator=(LibXlsSheet&& other) { + if (this != &other) { + std::swap(sandbox_, other.sandbox_); + std::swap(rws_, other.rws_); + std::swap(row_, other.row_); + std::swap(col_, other.col_); + } + return *this; + } + + private: + LibXlsSheet(LibxlsSapiSandbox* sandbox, xlsWorkSheet* rws, size_t row, + size_t col) + : sandbox_(CHECK_NOTNULL(sandbox)), rws_(rws), row_(row), col_(col) {} + + absl::StatusOr GetStr(const sapi::v::Struct& sapi_cell); + absl::StatusOr GetNewCell( + const sapi::v::Struct& sapi_cell); + + LibxlsSapiSandbox* sandbox_; + xlsWorkSheet* rws_ = nullptr; + size_t row_; + size_t col_; +}; + +class LibXlsWorkbook { + public: + static absl::StatusOr Open( + LibxlsSapiSandbox* sandbox, const std::string& filename, + const std::string& encode = "UTF-8"); + + size_t GetSheetCount(); + absl::StatusOr OpenSheet(uint32_t index); + + ~LibXlsWorkbook(); + + LibXlsWorkbook(LibXlsWorkbook&& other) { *this = std::move(other); } + + LibXlsWorkbook& operator=(LibXlsWorkbook&& other) { + if (this != &other) { + std::swap(sandbox_, other.sandbox_); + std::swap(rwb_, other.rwb_); + std::swap(sheet_count_, other.sheet_count_); + } + return *this; + } + + private: + LibXlsWorkbook(LibxlsSapiSandbox* sandbox, xlsWorkBook* rwb, size_t count) + : sandbox_(CHECK_NOTNULL(sandbox)), + rwb_(CHECK_NOTNULL(rwb)), + sheet_count_(count) {} + + LibxlsSapiSandbox* sandbox_; + xlsWorkBook* rwb_ = nullptr; + size_t sheet_count_; +}; + +#endif // CONTRIB_LIBPCAP_UTILS_UTILS_LIBPCAP_H_ diff --git a/contrib/libxls/xls.gen.h.in b/contrib/libxls/xls.gen.h.in new file mode 100644 index 0000000..8ab4980 --- /dev/null +++ b/contrib/libxls/xls.gen.h.in @@ -0,0 +1,21 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define FILE void +#undef __cplusplus +extern "C" { +#include "${libxls_SOURCE_DIR}/include/xls.h" +} +#define __cplusplus +#undef FILE