From 5be51d2e9bcb7023bb645d29a435c153b56fb196 Mon Sep 17 00:00:00 2001 From: Jan Marvin Garbuszus Date: Sat, 15 Jul 2023 14:28:42 +0200 Subject: [PATCH 1/9] read encrypted xlsx files --- DESCRIPTION | 2 + R/RcppExports.R | 4 + R/wb_load.R | 8 + configure | 78 + src/Makevars | 43 +- src/Makevars.in | 42 + src/RcppExports.cpp | 13 + src/decrypt.cpp | 12 + src/xlcpp/aes.cpp | 466 ++++ src/xlcpp/aes.h | 26 + src/xlcpp/b64.cpp | 106 + src/xlcpp/b64.h | 6 + src/xlcpp/cfbf.cpp | 847 ++++++++ src/xlcpp/cfbf.h | 77 + src/xlcpp/mmap.cpp | 472 +++++ src/xlcpp/mmap.h | 151 ++ src/xlcpp/sha1.cpp | 263 +++ src/xlcpp/sha1.h | 35 + src/xlcpp/sha512.cpp | 174 ++ src/xlcpp/sha512.h | 16 + src/xlcpp/utf16.h | 346 +++ src/xlcpp/xlcpp-pimpl.h | 364 ++++ src/xlcpp/xlcpp.cpp | 2070 ++++++++++++++++++ src/xlcpp/xlcpp.h | 155 ++ src/xlcpp/xlsb.cpp | 565 +++++ src/xlcpp/xlsb.h | 2707 ++++++++++++++++++++++++ src/xlcpp/xml-reader.cpp | 398 ++++ src/xlcpp/xml-writer.cpp | 77 + tests/testthat/helper.R | 3 +- tests/testthat/test-loading_workbook.R | 12 + 30 files changed, 9536 insertions(+), 2 deletions(-) create mode 100755 configure create mode 100644 src/Makevars.in create mode 100644 src/decrypt.cpp create mode 100644 src/xlcpp/aes.cpp create mode 100644 src/xlcpp/aes.h create mode 100644 src/xlcpp/b64.cpp create mode 100644 src/xlcpp/b64.h create mode 100644 src/xlcpp/cfbf.cpp create mode 100644 src/xlcpp/cfbf.h create mode 100644 src/xlcpp/mmap.cpp create mode 100644 src/xlcpp/mmap.h create mode 100644 src/xlcpp/sha1.cpp create mode 100644 src/xlcpp/sha1.h create mode 100644 src/xlcpp/sha512.cpp create mode 100644 src/xlcpp/sha512.h create mode 100644 src/xlcpp/utf16.h create mode 100644 src/xlcpp/xlcpp-pimpl.h create mode 100644 src/xlcpp/xlcpp.cpp create mode 100644 src/xlcpp/xlcpp.h create mode 100644 src/xlcpp/xlsb.cpp create mode 100644 src/xlcpp/xlsb.h create mode 100644 src/xlcpp/xml-reader.cpp create mode 100644 src/xlcpp/xml-writer.cpp diff --git a/DESCRIPTION b/DESCRIPTION index befc45c3d..40b2ff2fb 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -43,3 +43,5 @@ Roxygen: list(markdown = TRUE) Config/testthat/edition: 3 Config/testthat/parallel: false Config/testthat/start-first: aaa +SystemRequirements: C++20, libarchive: libarchive-dev (deb), + libarchive-devel (rpm), libarchive (homebrew), libarchive_dev (csw) diff --git a/R/RcppExports.R b/R/RcppExports.R index 3ab1ad0b4..212d4424d 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -1,6 +1,10 @@ # Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 +read_encryption <- function(PATH, OUT, PASSWORD) { + invisible(.Call(`_openxlsx2_read_encryption`, PATH, OUT, PASSWORD)) +} + #' Check if path is to long to be an R file path #' @param path the file path used in file.exists() #' @noRd diff --git a/R/wb_load.R b/R/wb_load.R index 29d9a5309..3c2b5681a 100644 --- a/R/wb_load.R +++ b/R/wb_load.R @@ -49,6 +49,14 @@ wb_load <- function( stop("File does not exist.") } + pwd <- list(...)$password + + if (!is.null(pwd)) { + unencrypted_xlsx <- temp_xlsx() + read_encryption(PATH = path.expand(file), OUT = unencrypted_xlsx, PASSWORD = pwd) + file <- unencrypted_xlsx + } + ## create temp dir xmlDir <- temp_dir("_openxlsx_wb_load") diff --git a/configure b/configure new file mode 100755 index 000000000..e984c6134 --- /dev/null +++ b/configure @@ -0,0 +1,78 @@ +# Anticonf (tm) script by Jeroen Ooms, Jim Hester (2017) +# This script will query 'pkg-config' for the required cflags and ldflags. +# If pkg-config is unavailable or does not find the library, try setting +# INCLUDE_DIR and LIB_DIR manually via e.g: +# R CMD INSTALL --configure-vars='INCLUDE_DIR=/.../include LIB_DIR=/.../lib' + +# Library settings +PKG_CONFIG_NAME="libarchive" +PKG_DEB_NAME="libarchive-dev" +PKG_RPM_NAME="libarchive-devel" +PKG_CSW_NAME="libarchive_dev" +PKG_BREW_NAME="libarchive" +PKG_TEST_HEADER="" +PKG_LIBS=-larchive + +# Use pkg-config if available +pkg-config ${PKG_CONFIG_NAME} --atleast-version=1.0 2>/dev/null +if [ $? -eq 0 ]; then + PKGCONFIG_CFLAGS=`pkg-config --cflags ${PKG_CONFIG_NAME}` + PKGCONFIG_LIBS=`pkg-config --libs ${PKG_CONFIG_NAME}` +fi + +# Note that cflags may be empty in case of success +if [ "$INCLUDE_DIR" ] || [ "$LIB_DIR" ]; then + echo "Found INCLUDE_DIR and/or LIB_DIR!" + PKG_CFLAGS="-I$INCLUDE_DIR $PKG_CFLAGS" + PKG_LIBS="-L$LIB_DIR $PKG_LIBS" +elif [ "$PKGCONFIG_CFLAGS" ] || [ "$PKGCONFIG_LIBS" ]; then + echo "Found pkg-config cflags and libs!" + PKG_CFLAGS=${PKGCONFIG_CFLAGS} + PKG_LIBS=${PKGCONFIG_LIBS} +elif [ `uname` = "Darwin" ]; then + test ! "$CI" && brew --version 2>/dev/null + if [ $? -eq 0 ]; then + BREWDIR=`brew --prefix` + PKG_CFLAGS="-I$BREWDIR/opt/libarchive/include" + PKG_LIBS="-L$BREWDIR/opt/libarchive/lib $PKG_LIBS" + else + curl -sfL "https://autobrew.github.io/scripts/$PKG_BREW_NAME" > autobrew + . ./autobrew + fi +fi + +# Find compiler +CXX20=`${R_HOME}/bin/R CMD config CXX20` +CXX20FLAGS=`${R_HOME}/bin/R CMD config CXX20FLAGS` +CPPFLAGS=`${R_HOME}/bin/R CMD config CPPFLAGS` + +# For debugging +echo "PKG_CFLAGS=$PKG_CFLAGS" +echo "PKG_LIBS=$PKG_LIBS" + +# Test configuration +echo "#include $PKG_TEST_HEADER" | ${CXX20} ${CPPFLAGS} ${PKG_CFLAGS} ${CXX20FLAGS} -E -xc++ - > /dev/null + +# Customize the error +if [ $? -ne 0 ]; then + echo "--------------------------- [ANTICONF] --------------------------------" + echo "Configuration failed because $PKG_CONFIG_NAME was not found. Try installing:" + echo " * deb: $PKG_DEB_NAME (Debian, Ubuntu, etc)" + echo " * rpm: $PKG_RPM_NAME (Fedora, CentOS, RHEL)" + echo " * csw: $PKG_CSW_NAME (Solaris)" + echo " * brew: $PKG_BREW_NAME (Mac OSX)" + echo "If $PKG_CONFIG_NAME is already installed, check that 'pkg-config' is in your" + echo "PATH and PKG_CONFIG_PATH contains a $PKG_CONFIG_NAME.pc file. If pkg-config" + echo "is unavailable you can set INCLUDE_DIR and LIB_DIR manually via:" + echo "R CMD INSTALL --configure-vars='INCLUDE_DIR=... LIB_DIR=...'" + echo "-------------------------- [ERROR MESSAGE] ---------------------------" + cat configure.log + echo "--------------------------------------------------------------------" + exit 1 +fi + +# Write to Makevars +sed -e "s|@PKG_CXXFLAGS@|$PKG_CFLAGS|" -e "s|@PKG_LIBS@|$PKG_LIBS|" src/Makevars.in > src/Makevars + +# Success +exit 0 diff --git a/src/Makevars b/src/Makevars index ee4055f80..49045080d 100644 --- a/src/Makevars +++ b/src/Makevars @@ -1 +1,42 @@ -PKG_CPPFLAGS = -I. -I../inst/include/pugixml \ No newline at end of file + +#PKG_CPPFLAGS = -I. -I../inst/include/pugixml -Ixlcpp -DXLCPP_EXPORT +PKG_CXXFLAGS = -I. -Ixlcpp -I../inst/include/pugixml -DXLCPP_EXPORT + +#PKG_LIBS=-Lpugixml -Lcfbf -L/usr/lib -larchive -L/usr/lib -lfmt +PKG_LIBS = -larchive -Lpugixml -Lxlcpp -lfmt + +PKGROOT = ./xlcpp + +OBJECTS = decrypt.o \ + helper_functions.o \ + load_workbook.o \ + pugi.o \ + strings_xml.o \ + styles_xml.o \ + write_file.o \ + $(PKGROOT)/aes.o \ + $(PKGROOT)/b64.o \ + $(PKGROOT)/cfbf.o \ + $(PKGROOT)/mmap.o \ + $(PKGROOT)/sha1.o \ + $(PKGROOT)/sha512.o \ + $(PKGROOT)/xlcpp.o \ + $(PKGROOT)/xlsb.o \ + $(PKGROOT)/xml-reader.o \ + $(PKGROOT)/xml-writer.o \ + RcppExports.o + +XLCPP = $(PKGROOT)/aes.cpp \ + $(PKGROOT)/b64.cpp \ + $(PKGROOT)/cfbf.cpp \ + $(PKGROOT)/mmap.cpp \ + $(PKGROOT)/sha1.cpp \ + $(PKGROOT)/sha512.cpp \ + $(PKGROOT)/xml-reader.cpp \ + $(PKGROOT)/xml-writer.cpp \ + $(PKGROOT)/xlcpp.cpp \ + $(PKGROOT)/xlsb.cpp + +PUGIXML = ../inst/include/pugixml/pugixml.cpp + +# CXX_STD=CXX20 diff --git a/src/Makevars.in b/src/Makevars.in new file mode 100644 index 000000000..ca584e421 --- /dev/null +++ b/src/Makevars.in @@ -0,0 +1,42 @@ + +#PKG_CPPFLAGS = -I. -I../inst/include/pugixml -Ixlcpp -DXLCPP_EXPORT +PKG_CXXFLAGS = @PKG_CXXFLAGS@ -I. -Ixlcpp -I../inst/include/pugixml -DXLCPP_EXPORT + +#PKG_LIBS=-Lpugixml -Lcfbf -L/usr/lib -larchive -L/usr/lib -lfmt +PKG_LIBS = @PKG_LIBS@ -Lpugixml -Lxlcpp -lfmt + +PKGROOT = ./xlcpp + +OBJECTS = decrypt.o \ + helper_functions.o \ + load_workbook.o \ + pugi.o \ + strings_xml.o \ + styles_xml.o \ + write_file.o \ + $(PKGROOT)/aes.o \ + $(PKGROOT)/b64.o \ + $(PKGROOT)/cfbf.o \ + $(PKGROOT)/mmap.o \ + $(PKGROOT)/sha1.o \ + $(PKGROOT)/sha512.o \ + $(PKGROOT)/xlcpp.o \ + $(PKGROOT)/xlsb.o \ + $(PKGROOT)/xml-reader.o \ + $(PKGROOT)/xml-writer.o \ + RcppExports.o + +XLCPP = $(PKGROOT)/aes.cpp \ + $(PKGROOT)/b64.cpp \ + $(PKGROOT)/cfbf.cpp \ + $(PKGROOT)/mmap.cpp \ + $(PKGROOT)/sha1.cpp \ + $(PKGROOT)/sha512.cpp \ + $(PKGROOT)/xml-reader.cpp \ + $(PKGROOT)/xml-writer.cpp \ + $(PKGROOT)/xlcpp.cpp \ + $(PKGROOT)/xlsb.cpp + +PUGIXML = ../inst/include/pugixml/pugixml.cpp + +# CXX_STD=CXX20 diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 22ac1e9d4..fefe5b0ec 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -11,6 +11,18 @@ Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); #endif +// read_encryption +void read_encryption(std::string PATH, std::string OUT, std::string PASSWORD); +RcppExport SEXP _openxlsx2_read_encryption(SEXP PATHSEXP, SEXP OUTSEXP, SEXP PASSWORDSEXP) { +BEGIN_RCPP + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< std::string >::type PATH(PATHSEXP); + Rcpp::traits::input_parameter< std::string >::type OUT(OUTSEXP); + Rcpp::traits::input_parameter< std::string >::type PASSWORD(PASSWORDSEXP); + read_encryption(PATH, OUT, PASSWORD); + return R_NilValue; +END_RCPP +} // to_long bool to_long(std::string path); RcppExport SEXP _openxlsx2_to_long(SEXP pathSEXP) { @@ -842,6 +854,7 @@ END_RCPP } static const R_CallMethodDef CallEntries[] = { + {"_openxlsx2_read_encryption", (DL_FUNC) &_openxlsx2_read_encryption, 3}, {"_openxlsx2_to_long", (DL_FUNC) &_openxlsx2_to_long, 1}, {"_openxlsx2_openxlsx2_type", (DL_FUNC) &_openxlsx2_openxlsx2_type, 1}, {"_openxlsx2_int_to_col", (DL_FUNC) &_openxlsx2_int_to_col, 1}, diff --git a/src/decrypt.cpp b/src/decrypt.cpp new file mode 100644 index 000000000..e0de3cd74 --- /dev/null +++ b/src/decrypt.cpp @@ -0,0 +1,12 @@ +#include + +// [[Rcpp::export]] +void read_encryption(std::string PATH, std::string OUT, std::string PASSWORD) { + + const std::filesystem::path path = PATH; + + xlcpp::workbook wb(path, PASSWORD, OUT); + + // this creates xlcpp workbook, not the unzipped xlsx file + // wb.save(OUT); +} diff --git a/src/xlcpp/aes.cpp b/src/xlcpp/aes.cpp new file mode 100644 index 000000000..683b2c397 --- /dev/null +++ b/src/xlcpp/aes.cpp @@ -0,0 +1,466 @@ +/* + +This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode. +Block size can be chosen in aes.h - available choices are AES128, AES192, AES256. + +The implementation is verified against the test vectors in: + National Institute of Standards and Technology Special Publication 800-38A 2001 ED + +ECB-AES128 +---------- + + plain-text: + 6bc1bee22e409f96e93d7e117393172a + ae2d8a571e03ac9c9eb76fac45af8e51 + 30c81c46a35ce411e5fbc1191a0a52ef + f69f2445df4f9b17ad2b417be66c3710 + + key: + 2b7e151628aed2a6abf7158809cf4f3c + + resulting cipher + 3ad77bb40d7a3660a89ecaf32466ef97 + f5d3d58503b9699de785895a96fdbaaf + 43b1cd7f598ece23881b00e3ed030688 + 7b0c785e27e8ad3f8223207104725dd4 + + +NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) + You should pad the end of the string with zeros if this is not the case. + For AES192/256 the key size is proportionally larger. + +*/ + +/*****************************************************************************/ +/* Includes: */ +/*****************************************************************************/ +#include "aes.h" +#include + +/*****************************************************************************/ +/* Defines: */ +/*****************************************************************************/ +// The number of columns comprising a state in AES. This is a constant in AES. Value=4 +#define Nb 4 + +#define Nk_128 4 // The number of 32 bit words in a key. +#define Nr_128 10 // The number of rounds in AES Cipher. + +#define Nk_256 8 +#define Nr_256 14 + +/*****************************************************************************/ +/* Private variables: */ +/*****************************************************************************/ +// state - array holding the intermediate results during decryption. +typedef uint8_t state_t[4][4]; + +// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM +// The numbers below can be computed dynamically trading ROM for RAM - +// This can be useful in (embedded) bootloader applications, where ROM is often limited. +static const uint8_t sbox[256] = { + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; + +static const uint8_t rsbox[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; + +// The round constant word array, Rcon[i], contains the values given by +// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) +static const uint8_t Rcon[11] = { + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + +// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. +template +static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) { + uint8_t tempa[4]; // Used for the column/row operations + + // The first round key is the key itself. + for (unsigned int i = 0; i < Nk; i++) { + RoundKey[i * 4] = Key[i * 4]; + RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; + RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; + RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; + } + + // All other round keys are found from the previous round keys. + for (unsigned int i = Nk; i < Nb * (Nr + 1); i++) { + tempa[0] = RoundKey[(i * 4) - 4]; + tempa[1] = RoundKey[(i * 4) - 3]; + tempa[2] = RoundKey[(i * 4) - 2]; + tempa[3] = RoundKey[(i * 4) - 1]; + + if (i % Nk == 0) { + // This function shifts the 4 bytes in a word to the left once. + // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] + + // Function RotWord() + { + const uint8_t u8tmp = tempa[0]; + tempa[0] = tempa[1]; + tempa[1] = tempa[2]; + tempa[2] = tempa[3]; + tempa[3] = u8tmp; + } + + // SubWord() is a function that takes a four-byte input word and + // applies the S-box to each of the four bytes to produce an output word. + + // Function Subword() + { + tempa[0] = sbox[tempa[0]]; + tempa[1] = sbox[tempa[1]]; + tempa[2] = sbox[tempa[2]]; + tempa[3] = sbox[tempa[3]]; + } + + tempa[0] = tempa[0] ^ Rcon[i/Nk]; + } + + if constexpr (Nk == Nk_256) { + if (i % Nk == 4) { + // Function Subword() + tempa[0] = sbox[tempa[0]]; + tempa[1] = sbox[tempa[1]]; + tempa[2] = sbox[tempa[2]]; + tempa[3] = sbox[tempa[3]]; + } + } + + RoundKey[i * 4] = RoundKey[(i - Nk) * 4] ^ tempa[0]; + RoundKey[(i * 4) + 1] = RoundKey[((i - Nk) * 4) + 1] ^ tempa[1]; + RoundKey[(i * 4) + 2] = RoundKey[((i - Nk) * 4) + 2] ^ tempa[2]; + RoundKey[(i * 4) + 3] = RoundKey[((i - Nk) * 4) + 3] ^ tempa[3]; + } +} + +void AES128_init_ctx(struct AES_ctx* ctx, const uint8_t* key) { + KeyExpansion(ctx->RoundKey, key); +} + +void AES128_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) { + KeyExpansion(ctx->RoundKey, key); + memcpy(ctx->Iv, iv, AES_BLOCKLEN); +} + +void AES256_init_ctx(struct AES_ctx* ctx, const uint8_t* key) { + KeyExpansion(ctx->RoundKey, key); +} + +void AES256_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) { + KeyExpansion(ctx->RoundKey, key); + memcpy(ctx->Iv, iv, AES_BLOCKLEN); +} + +// This function adds the round key to state. +// The round key is added to the state by an XOR function. +static void AddRoundKey(uint8_t round, state_t& state, const uint8_t* RoundKey) { + for (uint8_t i = 0; i < 4; i++) { + for (uint8_t j = 0; j < 4; ++j) { + state[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j]; + } + } +} + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void SubBytes(state_t& state) { + for (uint8_t i = 0; i < 4; i++) { + for (uint8_t j = 0; j < 4; j++) { + state[j][i] = sbox[state[j][i]]; + } + } +} + +// The ShiftRows() function shifts the rows in the state to the left. +// Each row is shifted with different offset. +// Offset = Row number. So the first row is not shifted. +static void ShiftRows(state_t& state) { + uint8_t temp; + + // Rotate first row 1 columns to left + temp = state[0][1]; + state[0][1] = state[1][1]; + state[1][1] = state[2][1]; + state[2][1] = state[3][1]; + state[3][1] = temp; + + // Rotate second row 2 columns to left + temp = state[0][2]; + state[0][2] = state[2][2]; + state[2][2] = temp; + + temp = state[1][2]; + state[1][2] = state[3][2]; + state[3][2] = temp; + + // Rotate third row 3 columns to left + temp = state[0][3]; + state[0][3] = state[3][3]; + state[3][3] = state[2][3]; + state[2][3] = state[1][3]; + state[1][3] = temp; +} + +static constexpr uint8_t galois_double(uint8_t x) { + return (uint8_t)((x << 1) ^ (((x >> 7) & 1) * 0x1b)); +} + +static_assert(galois_double(0x00) == 0x00); +static_assert(galois_double(0x01) == 0x02); +static_assert(galois_double(0x7f) == 0xfe); +static_assert(galois_double(0x80) == 0x1b); +static_assert(galois_double(0xff) == 0xe5); + +// MixColumns function mixes the columns of the state matrix +static void MixColumns(state_t& state) { + for (uint8_t i = 0; i < 4; i++) { + auto t = state[i][0]; + uint8_t tmp = state[i][0] ^ state[i][1] ^ state[i][2] ^ state[i][3]; + + for (unsigned int j = 0; j < 4; j++) { + uint8_t tm = state[i][j]; + + if (j == 3) + tm ^= t; + else + tm ^= state[i][j+1]; + + tm = galois_double(tm); + state[i][j] ^= tm ^ tmp; + } + } +} + +// Multiply is used to multiply numbers in the field GF(2^8) +static constexpr uint8_t Multiply(uint8_t x, uint8_t y) { + uint8_t ret = (y & 1) * x; + + x = galois_double(x); + + if (y & 2) + ret ^= x; + + x = galois_double(x); + + if (y & 4) + ret ^= x; + + if (y & 8) { + x = galois_double(x); + ret ^= x; + } + + return ret; +} + +// MixColumns function mixes the columns of the state matrix. +// The method used to multiply may be difficult to understand for the inexperienced. +// Please use the references to gain more information. +static void InvMixColumns(state_t& state) { + for (unsigned int i = 0; i < 4; i++) { + auto a = state[i][0]; + auto b = state[i][1]; + auto c = state[i][2]; + auto d = state[i][3]; + + state[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); + state[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); + state[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); + state[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); + } +} + + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void InvSubBytes(state_t& state) { + for (uint8_t i = 0; i < 4; i++) { + for (uint8_t j = 0; j < 4; j++) { + state[j][i] = rsbox[state[j][i]]; + } + } +} + +static void InvShiftRows(state_t& state) { + uint8_t temp; + + // Rotate first row 1 columns to right + temp = state[3][1]; + state[3][1] = state[2][1]; + state[2][1] = state[1][1]; + state[1][1] = state[0][1]; + state[0][1] = temp; + + // Rotate second row 2 columns to right + temp = state[0][2]; + state[0][2] = state[2][2]; + state[2][2] = temp; + + temp = state[1][2]; + state[1][2] = state[3][2]; + state[3][2] = temp; + + // Rotate third row 3 columns to right + temp = state[0][3]; + state[0][3] = state[1][3]; + state[1][3] = state[2][3]; + state[2][3] = state[3][3]; + state[3][3] = temp; +} + +// Cipher is the main function that encrypts the PlainText. +template +static void Cipher(state_t& state, const uint8_t* RoundKey) { + // Add the First round key to the state before starting the rounds. + AddRoundKey(0, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr rounds are executed in the loop below. + // Last one without MixColumns() + for (uint8_t round = 1; ; round++) { + SubBytes(state); + ShiftRows(state); + + if (round == Nr) + break; + + MixColumns(state); + AddRoundKey(round, state, RoundKey); + } + + // Add round key to last round + AddRoundKey(Nr, state, RoundKey); +} + +template +static void InvCipher(state_t& state, const uint8_t* RoundKey) { + // Add the First round key to the state before starting the rounds. + AddRoundKey(Nr, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr rounds are executed in the loop below. + // Last one without InvMixColumn() + for (uint8_t round = Nr - 1; ; round--) { + InvShiftRows(state); + InvSubBytes(state); + AddRoundKey(round, state, RoundKey); + + if (round == 0) + break; + + InvMixColumns(state); + } +} + +/*****************************************************************************/ +/* Public functions: */ +/*****************************************************************************/ + +static void XorWithIv(uint8_t* buf, const uint8_t* Iv) { + for (uint8_t i = 0; i < AES_BLOCKLEN; i++) { // The block in AES is always 128bit no matter the key size + buf[i] ^= Iv[i]; + } +} + +void AES128_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf) { + // The next function call encrypts the PlainText with the Key using AES algorithm. + Cipher(*(state_t*)buf, ctx->RoundKey); +} + +void AES128_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf) { + // The next function call decrypts the PlainText with the Key using AES algorithm. + InvCipher(*(state_t*)buf, ctx->RoundKey); +} + +void AES128_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) { + auto Iv = ctx->Iv; + + for (size_t i = 0; i < length; i += AES_BLOCKLEN) { + XorWithIv(buf, Iv); + Cipher(*(state_t*)buf, ctx->RoundKey); + Iv = buf; + buf += AES_BLOCKLEN; + } + /* store Iv in ctx for next call */ + memcpy(ctx->Iv, Iv, AES_BLOCKLEN); +} + +void AES128_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) { + uint8_t storeNextIv[AES_BLOCKLEN]; + + for (size_t i = 0; i < length; i += AES_BLOCKLEN) { + memcpy(storeNextIv, buf, AES_BLOCKLEN); + InvCipher(*(state_t*)buf, ctx->RoundKey); + XorWithIv(buf, ctx->Iv); + memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN); + buf += AES_BLOCKLEN; + } +} + +void AES256_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf) { + // The next function call encrypts the PlainText with the Key using AES algorithm. + Cipher(*(state_t*)buf, ctx->RoundKey); +} + +void AES256_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf) { + // The next function call decrypts the PlainText with the Key using AES algorithm. + InvCipher(*(state_t*)buf, ctx->RoundKey); +} + +void AES256_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) { + auto Iv = ctx->Iv; + + for (size_t i = 0; i < length; i += AES_BLOCKLEN) { + XorWithIv(buf, Iv); + Cipher(*(state_t*)buf, ctx->RoundKey); + Iv = buf; + buf += AES_BLOCKLEN; + } + /* store Iv in ctx for next call */ + memcpy(ctx->Iv, Iv, AES_BLOCKLEN); +} + +void AES256_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) { + uint8_t storeNextIv[AES_BLOCKLEN]; + + for (size_t i = 0; i < length; i += AES_BLOCKLEN) { + memcpy(storeNextIv, buf, AES_BLOCKLEN); + InvCipher(*(state_t*)buf, ctx->RoundKey); + XorWithIv(buf, ctx->Iv); + memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN); + buf += AES_BLOCKLEN; + } +} diff --git a/src/xlcpp/aes.h b/src/xlcpp/aes.h new file mode 100644 index 000000000..bbe1d63c2 --- /dev/null +++ b/src/xlcpp/aes.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +#define AES_BLOCKLEN 16 // Block length in bytes - AES is 128b block only +#define AES_keyExpSize 240 + +struct AES_ctx { + uint8_t RoundKey[AES_keyExpSize]; + uint8_t Iv[AES_BLOCKLEN]; +}; + +void AES128_init_ctx(struct AES_ctx* ctx, const uint8_t* key); +void AES128_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); +void AES128_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf); +void AES128_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf); +void AES128_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); +void AES128_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); + +void AES256_init_ctx(struct AES_ctx* ctx, const uint8_t* key); +void AES256_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); +void AES256_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf); +void AES256_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf); +void AES256_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); +void AES256_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); diff --git a/src/xlcpp/b64.cpp b/src/xlcpp/b64.cpp new file mode 100644 index 000000000..35250950a --- /dev/null +++ b/src/xlcpp/b64.cpp @@ -0,0 +1,106 @@ +/* +* Base64 encoding/decoding (RFC1341) +* Copyright (c) 2005-2011, Jouni Malinen +* +* This software may be distributed under the terms of the BSD license. +* See README for more details. +*/ + +// 2016-12-12 - Gaspard Petit : Slightly modified to return a std::string +// instead of a buffer allocated with malloc. + +#include +#include "b64.h" + +static const unsigned char base64_table[65] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/** +* base64_encode - Base64 encode +* @src: Data to be encoded +* @len: Length of the data to be encoded +* @out_len: Pointer to output length variable, or %NULL if not used +* Returns: Allocated buffer of out_len bytes of encoded data, +* or empty string on failure +*/ +std::string b64encode(std::string_view sv) { + const unsigned char* src = (const unsigned char*)sv.data(); + size_t len = sv.length(); + unsigned char *out, *pos; + const unsigned char *end, *in; + + size_t olen; + + olen = 4*((len + 2) / 3); /* 3-byte blocks to 4-byte */ + + if (olen < len) + return std::string(); /* integer overflow */ + + std::string outStr; + outStr.resize(olen); + out = (unsigned char*)&outStr[0]; + + end = src + len; + in = src; + pos = out; + while (end - in >= 3) { + *pos++ = base64_table[in[0] >> 2]; + *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; + *pos++ = base64_table[in[2] & 0x3f]; + in += 3; + } + + if (end - in) { + *pos++ = base64_table[in[0] >> 2]; + if (end - in == 1) { + *pos++ = base64_table[(in[0] & 0x03) << 4]; + *pos++ = '='; + } + else { + *pos++ = base64_table[((in[0] & 0x03) << 4) | + (in[1] >> 4)]; + *pos++ = base64_table[(in[1] & 0x0f) << 2]; + } + *pos++ = '='; + } + + return outStr; +} + +static const int B64index[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 63, + 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 +}; + +std::string b64decode(std::string_view sv) { + auto p = (unsigned char*)sv.data(); + int pad = sv.length() > 0 && (sv.length() % 4 || p[sv.length() - 1] == '='); + const size_t L = ((sv.length() + 3) / 4 - pad) * 4; + std::string str(L / 4 * 3 + pad, '\0'); + + for (size_t i = 0, j = 0; i < L; i += 4) { + int n = B64index[p[i]] << 18 | B64index[p[i + 1]] << 12 | B64index[p[i + 2]] << 6 | B64index[p[i + 3]]; + str[j++] = (char)(n >> 16); + str[j++] = (char)(n >> 8 & 0xFF); + str[j++] = (char)(n & 0xFF); + } + + if (pad) { + int n = B64index[p[L]] << 18 | B64index[p[L + 1]] << 12; + str[str.size() - 1] = (char)(n >> 16); + + if (sv.length() > L + 2 && p[L + 2] != '=') { + n |= B64index[p[L + 2]] << 6; + str.push_back((char)(n >> 8 & 0xFF)); + } + } + + return str; +} diff --git a/src/xlcpp/b64.h b/src/xlcpp/b64.h new file mode 100644 index 000000000..01dfaa9cb --- /dev/null +++ b/src/xlcpp/b64.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +std::string b64encode(std::string_view sv); +std::string b64decode(std::string_view sv); diff --git a/src/xlcpp/cfbf.cpp b/src/xlcpp/cfbf.cpp new file mode 100644 index 000000000..94896d1dc --- /dev/null +++ b/src/xlcpp/cfbf.cpp @@ -0,0 +1,847 @@ +#include "openxlsx2.h" + +#include +#include +#include +#include "cfbf.h" +#include "utf16.h" +#include "sha1.h" +#include "sha512.h" +#include "aes.h" +#include "b64.h" +#include "xlcpp-pimpl.h" + +using namespace std; + +static const uint32_t NOSTREAM = 0xffffffff; + +struct structured_storage_header { + uint64_t sig; + uint8_t clsid[16]; + uint16_t minor_version; + uint16_t major_version; + uint16_t byte_order; + uint16_t sector_shift; + uint16_t mini_sector_shift; + uint16_t reserved1; + uint32_t reserved2; + uint32_t num_sect_dir; + uint32_t num_sect_fat; + uint32_t sect_dir_start; + uint32_t transaction_signature; + uint32_t mini_sector_cutoff; + uint32_t mini_fat_start; + uint32_t num_sect_mini_fat; + uint32_t sect_dif_start; + uint32_t num_sect_dif; + uint32_t sect_dif[109]; +}; + +static_assert(sizeof(structured_storage_header) == 0x200); + +enum class obj_type : uint8_t { + STGTY_INVALID = 0, + STGTY_STORAGE = 1, + STGTY_STREAM = 2, + STGTY_LOCKBYTES = 3, + STGTY_PROPERTY = 4, + STGTY_ROOT = 5 +}; + +enum class tree_colour : uint8_t { + red = 0, + black = 1 +}; + +#pragma pack(push,1) + +struct dirent { + char16_t name[32]; + uint16_t name_len; + obj_type type; + tree_colour colour; + uint32_t sid_left_sibling; + uint32_t sid_right_sibling; + uint32_t sid_child; + uint8_t clsid[16]; + uint32_t user_flags; + uint64_t create_time; + uint64_t modify_time; + uint32_t sect_start; + uint64_t size; +}; + +#pragma pack(pop) + +static_assert(sizeof(dirent) == 0x80); + +static const string_view NS_ENCRYPTION = "http://schemas.microsoft.com/office/2006/encryption"; +static const string_view NS_PASSWORD = "http://schemas.microsoft.com/office/2006/keyEncryptor/password"; + +cfbf::cfbf(span s) : s(s) { + auto& ssh = *(structured_storage_header*)s.data(); + + if (ssh.sig != CFBF_SIGNATURE) + Rcpp::stop("Incorrect signature."); + + auto& de = *(dirent*)(s.data() + (ssh.sect_dir_start + 1) * (1 << ssh.sector_shift)); + + if (de.type != obj_type::STGTY_ROOT) + Rcpp::stop("Root directory entry did not have type STGTY_ROOT."); + + add_entry("", 0, false); +} + +const dirent& cfbf::find_dirent(uint32_t num) { + auto& ssh = *(structured_storage_header*)s.data(); + + auto dirents_per_sector = (1 << ssh.sector_shift) / sizeof(dirent); + auto sector_skip = num / dirents_per_sector; + auto sector = ssh.sect_dir_start; + + while (sector_skip > 0) { + sector = next_sector(sector); + sector_skip--; + } + + return *(dirent*)(s.data() + ((sector + 1) << ssh.sector_shift) + ((num % dirents_per_sector) * sizeof(dirent))); +} + +void cfbf::add_entry(string_view path, uint32_t num, bool ignore_right) { + const auto& de = find_dirent(num); + + if (de.sid_left_sibling != NOSTREAM) + add_entry(path, de.sid_left_sibling, true); + + auto name = de.name_len >= sizeof(char16_t) && num != 0 ? utf16_to_utf8(u16string_view(de.name, (de.name_len / sizeof(char16_t)) - 1)) : ""; + + entries.emplace_back(*this, de, string(path) + name); + + if (de.sid_child != NOSTREAM) + add_entry(string(path) + string(name) + "/", de.sid_child, false); + + if (!ignore_right && de.sid_right_sibling != NOSTREAM) + add_entry(path, de.sid_right_sibling, false); +} + +cfbf_entry::cfbf_entry(cfbf& file, const dirent& de, string_view name) : file(file), de(de), name(name) { +} + +uint32_t cfbf::next_sector(uint32_t sector) const { + auto& ssh = *(structured_storage_header*)s.data(); + auto sectors_per_dif = (1 << ssh.sector_shift) / sizeof(uint32_t); + auto fat = (uint32_t*)(s.data() + ((ssh.sect_dif[sector / sectors_per_dif] + 1) << ssh.sector_shift)); + + return fat[sector % sectors_per_dif]; +} + +uint32_t cfbf::next_mini_sector(uint32_t sector) const { + auto& ssh = *(structured_storage_header*)s.data(); + auto mini_fat = (uint32_t*)(s.data() + ((ssh.mini_fat_start + 1) << ssh.sector_shift)); + + return mini_fat[sector]; +} + +size_t cfbf_entry::read(span buf, uint64_t off) const { + auto& ssh = *(structured_storage_header*)file.s.data(); + + if (off >= de.size) + return 0; + + if (off + buf.size() > de.size) + buf = buf.subspan(0, de.size - off); + + size_t read = 0; + + if (de.size < ssh.mini_sector_cutoff) { + auto mini_sector = de.sect_start; + auto mini_sector_skip = off >> ssh.mini_sector_shift; + + for (unsigned int i = 0; i < mini_sector_skip; i++) { + mini_sector = file.next_mini_sector(mini_sector); + } + + auto mini_sectors_per_sector = 1 << (ssh.sector_shift - ssh.mini_sector_shift); + + do { + auto mini_stream_sector = mini_sector / mini_sectors_per_sector; + auto sector = file.entries[0].de.sect_start; + + while (mini_stream_sector > 0) { + sector = file.next_sector(sector); + mini_stream_sector--; + } + + auto src = file.s.subspan(((sector + 1) << ssh.sector_shift) + ((mini_sector % mini_sectors_per_sector) << ssh.mini_sector_shift), 1 << ssh.mini_sector_shift); + auto to_copy = min(src.size(), buf.size()); + + memcpy(buf.data(), src.data(), to_copy); + + read += to_copy; + buf = buf.subspan(to_copy); + + if (buf.empty()) + break; + + mini_sector = file.next_mini_sector(mini_sector); + } while (true); + } else { + auto sector = de.sect_start; + auto sector_skip = off >> ssh.sector_shift; + + for (unsigned int i = 0; i < sector_skip; i++) { + sector = file.next_sector(sector); + } + + do { + auto src = file.s.subspan((sector + 1) << ssh.sector_shift, 1 << ssh.sector_shift); + auto to_copy = min(src.size(), buf.size()); + + memcpy(buf.data(), src.data(), to_copy); + + read += to_copy; + buf = buf.subspan(to_copy); + + if (buf.empty()) + break; + + sector = file.next_sector(sector); + } while (true); + } + + return read; +} + +size_t cfbf_entry::get_size() const { + return de.size; +} + +static array generate_key(u16string_view password, span salt, unsigned int spin_count) { + array h; + + { + SHA1_CTX ctx; + + ctx.update(salt); + ctx.update(span((uint8_t*)password.data(), password.size() * sizeof(char16_t))); + + ctx.finalize(h); + } + + for (uint32_t i = 0; i < spin_count; i++) { + SHA1_CTX ctx; + + ctx.update(span((uint8_t*)&i, sizeof(uint32_t))); + ctx.update(h); + + ctx.finalize(h); + } + + { + SHA1_CTX ctx; + uint32_t block = 0; + + ctx.update(h); + ctx.update(span((uint8_t*)&block, sizeof(uint32_t))); + + ctx.finalize(h); + } + + array buf1 = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; + + for (unsigned int i = 0; auto c : h) { + buf1[i] ^= c; + i++; + } + + auto x1 = sha1(buf1); + + array ret; + memcpy(ret.data(), x1.data(), ret.size()); + + return ret; +} + +static void generate_key44_sha1(u16string_view password, span salt, unsigned int spin_count, + span block_key, span ret) { + array h; + + { + SHA1_CTX ctx; + + ctx.update(salt); + ctx.update(span((uint8_t*)password.data(), password.size() * sizeof(char16_t))); + + ctx.finalize(h); + } + + for (uint32_t i = 0; i < spin_count; i++) { + SHA1_CTX ctx; + + ctx.update(span((uint8_t*)&i, sizeof(uint32_t))); + ctx.update(h); + + ctx.finalize(h); + } + + { + SHA1_CTX ctx; + + ctx.update(h); + ctx.update(block_key); + + ctx.finalize(h); + } + + memcpy(ret.data(), h.data(), 16); +} + +static void generate_key44_sha512(u16string_view password, span salt, unsigned int spin_count, + span block_key, span ret) { + array h; + + { + sha512_state ctx; + + sha_init(ctx); + sha_process(ctx, salt.data(), (uint32_t)salt.size()); + sha_process(ctx, password.data(), (uint32_t)(password.size() * sizeof(char16_t))); + sha_done(ctx, h.data()); + } + + for (uint32_t i = 0; i < spin_count; i++) { + sha512_state ctx; + + sha_init(ctx); + sha_process(ctx, &i, sizeof(uint32_t)); + sha_process(ctx, h.data(), h.size()); + sha_done(ctx, h.data()); + } + + { + sha512_state ctx; + + sha_init(ctx); + sha_process(ctx, h.data(), h.size()); + sha_process(ctx, block_key.data(), (uint32_t)block_key.size()); + sha_done(ctx, h.data()); + } + + memcpy(ret.data(), h.data(), 64); +} + +#pragma pack(push, 1) + +struct encryption_info { + uint16_t major; + uint16_t minor; + uint32_t flags; + uint32_t header_size; +}; + +struct encryption_header { + uint32_t flags; + uint32_t size_extra; + uint32_t alg_id; + uint32_t alg_id_hash; + uint32_t key_size; + uint32_t provider_type; + uint32_t reserved1; + uint32_t reserved2; + char16_t csp_name[0]; +}; + +#pragma pack(pop) + +static const uint32_t ALG_ID_AES_128 = 0x660e; +static const uint32_t ALG_ID_SHA_1 = 0x8004; + +void cfbf::check_password(u16string_view password, span salt, + span encrypted_verifier, + span encrypted_verifier_hash) { + auto key = generate_key(password, salt, 50000); + AES_ctx ctx; + array verifier; + array verifier_hash; + + if (encrypted_verifier.size() != verifier.size()) + Rcpp::stop("encrypted_verifier.size() was {}, expected {}", encrypted_verifier.size(), verifier.size()); + + if (encrypted_verifier_hash.size() != verifier_hash.size()) + Rcpp::stop("encrypted_verifier_hash.size() was {}, expected {}", encrypted_verifier_hash.size(), verifier_hash.size()); + + AES128_init_ctx(&ctx, key.data()); + + memcpy(verifier.data(), encrypted_verifier.data(), encrypted_verifier.size()); + + AES128_ECB_decrypt(&ctx, verifier.data()); + +#if 0 + fmt::print("verifier = "); + for (auto c : verifier) { + fmt::print("{:02x} ", c); + } + fmt::print("\n"); +#endif + + memcpy(verifier_hash.data(), encrypted_verifier_hash.data(), encrypted_verifier_hash.size()); + + AES128_ECB_decrypt(&ctx, verifier_hash.data()); + AES128_ECB_decrypt(&ctx, verifier_hash.data() + 16); + +#if 0 + fmt::print("verifier hash = "); + for (auto c : verifier_hash) { + fmt::print("{:02x} ", c); + } + fmt::print("\n"); +#endif + + auto hash = sha1(verifier); + + if (memcmp(hash.data(), verifier_hash.data(), hash.size())) + Rcpp::stop("Incorrect password."); + + key_size = 16; + memcpy(this->key.data(), key.data(), key_size); +} + +void cfbf::parse_enc_info_44(span enc_info, u16string_view password) { + enc_info = enc_info.subspan(sizeof(uint32_t)); + + if (enc_info.size() < sizeof(uint32_t) || *(uint32_t*)enc_info.data() != 0x40) + Rcpp::stop("EncryptionInfo reserved value was not 0x40."); + + enc_info = enc_info.subspan(sizeof(uint32_t)); + + xml_reader r(string_view((char*)enc_info.data(), enc_info.size())); + + bool found_root = false, found_key_data = false, found_password = false; + + while (r.read()) { + if (r.node_type() == xml_node::element) { + if (!found_root) { + if (r.local_name() != "encryption" || !r.namespace_uri_raw().cmp(NS_ENCRYPTION)) + Rcpp::stop("Root tag was {{{}}}{}, expected {{{}}}encryption.", + r.namespace_uri_raw().decode(), r.local_name(), NS_ENCRYPTION); + + found_root = true; + } else { + if (r.local_name() == "keyData" && r.namespace_uri_raw().cmp(NS_ENCRYPTION)) { + string salt_value_b64, cipher_algorithm, key_bits_str, cipher_chaining, hash_algorithm; + unsigned int key_bits; + + r.attributes_loop_raw([&](string_view local_name, xml_enc_string_view namespace_uri_raw, + xml_enc_string_view value_raw) { + + if (local_name == "saltValue") + salt_value_b64 = value_raw.decode(); + else if (local_name == "cipherAlgorithm") + cipher_algorithm = value_raw.decode(); + else if (local_name == "keyBits") + key_bits_str = value_raw.decode(); + else if (local_name == "cipherChaining") + cipher_chaining = value_raw.decode(); + else if (local_name == "hashAlgorithm") + hash_algorithm = value_raw.decode(); + + return true; + }); + + if (salt_value_b64.empty()) + Rcpp::stop("saltValue not set"); + + if (cipher_algorithm.empty()) + Rcpp::stop("cipherAlgorithm not set"); + + if (key_bits_str.empty()) + Rcpp::stop("keyBits not set"); + + if (cipher_chaining.empty()) + Rcpp::stop("cipherChaining not set"); + + if (hash_algorithm.empty()) + Rcpp::stop("hashAlgorithm not set"); + + auto salt_value = b64decode(salt_value_b64); + + if (cipher_algorithm != "AES") + Rcpp::stop("cipherAlgorithm was {}, expected AES", cipher_algorithm); + + { + auto [ptr, ec] = from_chars(key_bits_str.data(), key_bits_str.data() + key_bits_str.size(), key_bits); + + if (ptr != key_bits_str.data() + key_bits_str.size()) + Rcpp::stop("Could not convert \"{}\" to integer.", key_bits_str); + } + + if (key_bits != 128 && key_bits != 256) + Rcpp::stop("keyBits was {}, expected 128 or 256", key_bits); + + if (cipher_chaining != "ChainingModeCBC") + Rcpp::stop("cipherChaining was {}, expected ChainingModeCBC", cipher_chaining); + + if (hash_algorithm != "SHA1" && hash_algorithm != "SHA512") + Rcpp::stop("hashAlgorithm was {}, expected SHA1 or SHA512", hash_algorithm); + + memcpy(salt.data(), salt_value.data(), min(salt_value.size(), salt.size())); + found_key_data = true; + } else if (r.local_name() == "encryptedKey" && r.namespace_uri_raw().cmp(NS_PASSWORD)) { + string spin_count_str, salt_value_b64, cipher_algorithm, key_bits_str, cipher_chaining, hash_algorithm, + encrypted_verifier_hash_input_b64, encrypted_verifier_hash_value_b64, encrypted_key_value_b64; + unsigned int spin_count, key_bits; + + r.attributes_loop_raw([&](string_view local_name, xml_enc_string_view namespace_uri_raw, + xml_enc_string_view value_raw) { + + if (local_name == "spinCount") + spin_count_str = value_raw.decode(); + else if (local_name == "saltValue") + salt_value_b64 = value_raw.decode(); + else if (local_name == "cipherAlgorithm") + cipher_algorithm = value_raw.decode(); + else if (local_name == "keyBits") + key_bits_str = value_raw.decode(); + else if (local_name == "cipherChaining") + cipher_chaining = value_raw.decode(); + else if (local_name == "hashAlgorithm") + hash_algorithm = value_raw.decode(); + else if (local_name == "encryptedVerifierHashInput") + encrypted_verifier_hash_input_b64 = value_raw.decode(); + else if (local_name == "encryptedVerifierHashValue") + encrypted_verifier_hash_value_b64 = value_raw.decode(); + else if (local_name == "encryptedKeyValue") + encrypted_key_value_b64 = value_raw.decode(); + + return true; + }); + + if (spin_count_str.empty()) + Rcpp::stop("spinCount not set"); + + if (salt_value_b64.empty()) + Rcpp::stop("saltValue not set"); + + if (cipher_algorithm.empty()) + Rcpp::stop("cipherAlgorithm not set"); + + if (key_bits_str.empty()) + Rcpp::stop("keyBits not set"); + + if (cipher_chaining.empty()) + Rcpp::stop("cipherChaining not set"); + + if (hash_algorithm.empty()) + Rcpp::stop("hashAlgorithm not set"); + + if (encrypted_verifier_hash_input_b64.empty()) + Rcpp::stop("encryptedVerifierHashInput not set"); + + if (encrypted_verifier_hash_value_b64.empty()) + Rcpp::stop("encryptedVerifierHashValue not set"); + + if (encrypted_key_value_b64.empty()) + Rcpp::stop("encryptedKeyValue not set"); + + { + auto [ptr, ec] = from_chars(spin_count_str.data(), spin_count_str.data() + spin_count_str.size(), spin_count); + + if (ptr != spin_count_str.data() + spin_count_str.size()) + Rcpp::stop("Could not convert \"{}\" to integer.", spin_count_str); + } + + auto salt_value = b64decode(salt_value_b64); + + if (cipher_algorithm != "AES") + Rcpp::stop("cipherAlgorithm was {}, expected AES", cipher_algorithm); + + { + auto [ptr, ec] = from_chars(key_bits_str.data(), key_bits_str.data() + key_bits_str.size(), key_bits); + + if (ptr != key_bits_str.data() + key_bits_str.size()) + Rcpp::stop("Could not convert \"{}\" to integer.", key_bits_str); + } + + if (key_bits != 128 && key_bits != 256) + Rcpp::stop("keyBits was {}, expected 128 or 256", key_bits); + + if (cipher_chaining != "ChainingModeCBC") + Rcpp::stop("cipherChaining was {}, expected ChainingModeCBC", cipher_chaining); + + if (hash_algorithm == "SHA1") + hashalgo = hash_algorithm::sha1; + else if (hash_algorithm == "SHA512") + hashalgo = hash_algorithm::sha512; + else + Rcpp::stop("hashAlgorithm was {}, expected SHA1 or SHA512", hash_algorithm); + + auto encrypted_verifier_hash_input = b64decode(encrypted_verifier_hash_input_b64); + + auto encrypted_verifier_hash_value = b64decode(encrypted_verifier_hash_value_b64); + + auto encrypted_key_value = b64decode(encrypted_key_value_b64); + + static const array block1 = { 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 }; + static const array block2 = { 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e }; + static const array block3 = { 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 }; + + // FIXME - we can save time by saving the partial hash for key1, key2, and key3 + + array key1, key2, key3; + + if (hashalgo == hash_algorithm::sha512) + generate_key44_sha512(password, span((uint8_t*)salt_value.data(), salt_value.size()), spin_count, block1, key1); + else + generate_key44_sha1(password, span((uint8_t*)salt_value.data(), salt_value.size()), spin_count, block1, key1); + + // FIXME - extend key if short + + AES_ctx ctx; + array verifier; + array verifier_hash; + + if (encrypted_verifier_hash_input.size() != verifier.size()) + Rcpp::stop("encrypted_verifier_hash_input.size() was {}, expected {}", encrypted_verifier_hash_input.size(), verifier.size()); + + if (encrypted_verifier_hash_value.size() > verifier_hash.size()) + Rcpp::stop("encrypted_verifier_hash_value.size() was {}, expected at most {}", encrypted_verifier_hash_value.size(), verifier_hash.size()); + + array iv; + + memcpy(iv.data(), salt_value.data(), min(salt_value.size(), sizeof(iv))); + + if (salt_value.size() < sizeof(iv)) + memset(&iv[salt_value.size()], 0, sizeof(iv) - salt_value.size()); + + memcpy(verifier.data(), encrypted_verifier_hash_input.data(), encrypted_verifier_hash_input.size()); + + if (key_bits == 256) { + AES256_init_ctx_iv(&ctx, key1.data(), iv.data()); + AES256_CBC_decrypt_buffer(&ctx, verifier.data(), verifier.size()); + } else { + AES128_init_ctx_iv(&ctx, key1.data(), iv.data()); + AES128_CBC_decrypt_buffer(&ctx, verifier.data(), verifier.size()); + } + + memcpy(verifier_hash.data(), encrypted_verifier_hash_value.data(), encrypted_verifier_hash_value.size()); + + if (hashalgo == hash_algorithm::sha512) + generate_key44_sha512(password, span((uint8_t*)salt_value.data(), salt_value.size()), spin_count, block2, key2); + else + generate_key44_sha1(password, span((uint8_t*)salt_value.data(), salt_value.size()), spin_count, block2, key2); + + if (key_bits == 256) { + AES256_init_ctx_iv(&ctx, key2.data(), iv.data()); + AES256_CBC_decrypt_buffer(&ctx, verifier_hash.data(), verifier_hash.size()); + } else { + AES128_init_ctx_iv(&ctx, key2.data(), iv.data()); + AES128_CBC_decrypt_buffer(&ctx, verifier_hash.data(), verifier_hash.size()); + } + + if (hashalgo == hash_algorithm::sha512) { + array hash; + sha512_state ctx; + + sha_init(ctx); + sha_process(ctx, verifier.data(), (uint32_t)verifier.size()); + sha_done(ctx, hash.data()); + + if (memcmp(hash.data(), verifier_hash.data(), hash.size())) + Rcpp::stop("Incorrect password."); + } else { + auto hash = sha1(verifier); + if (memcmp(hash.data(), verifier_hash.data(), hash.size())) + Rcpp::stop("Incorrect password."); + } + + if (hashalgo == hash_algorithm::sha512) + generate_key44_sha512(password, span((uint8_t*)salt_value.data(), salt_value.size()), spin_count, block3, key3); + else + generate_key44_sha1(password, span((uint8_t*)salt_value.data(), salt_value.size()), spin_count, block3, key3); + + if (key_bits == 256) { + AES256_init_ctx_iv(&ctx, key3.data(), iv.data()); + AES256_CBC_decrypt_buffer(&ctx, (uint8_t*)encrypted_key_value.data(), encrypted_key_value.size()); + } else { + AES128_init_ctx_iv(&ctx, key3.data(), iv.data()); + AES128_CBC_decrypt_buffer(&ctx, (uint8_t*)encrypted_key_value.data(), encrypted_key_value.size()); + } + + key_size = key_bits / 8; + memcpy(key.data(), encrypted_key_value.data(), min((size_t)key_size, encrypted_key_value.size())); + + found_password = true; + } + } + } + } + + if (!found_key_data) + Rcpp::stop("keyData not found"); + + if (!found_password) + Rcpp::stop("encryptedKey not found"); + + agile_enc = true; +} + +void cfbf::parse_enc_info(span enc_info, u16string_view password) { + if (enc_info.size() < sizeof(encryption_info)) + Rcpp::stop("EncryptionInfo was {} bytes, expected at least {}", enc_info.size(), sizeof(encryption_info)); + + auto& ei = *(encryption_info*)enc_info.data(); + + if (ei.major == 4 && ei.minor == 4) { + parse_enc_info_44(enc_info, password); + return; + } else if (ei.major != 3 || ei.minor != 2) + Rcpp::stop("Unsupported EncryptionInfo version {}.{}", ei.major, ei.minor); + + if (ei.flags != 0x24) // AES + Rcpp::stop("Unsupported EncryptionInfo flags {:x}", ei.flags); + + if (ei.header_size < offsetof(encryption_header, csp_name)) + Rcpp::stop("Encryption header was {} bytes, expected at least {}", ei.header_size, offsetof(encryption_header, csp_name)); + + if (ei.header_size > enc_info.size() - sizeof(encryption_info)) + Rcpp::stop("Encryption header was {} bytes, but only {} remaining", ei.header_size, enc_info.size() - sizeof(encryption_info)); + + auto& h = *(encryption_header*)(enc_info.data() + sizeof(encryption_info)); + + if (h.alg_id != ALG_ID_AES_128) + Rcpp::stop("Unsupported algorithm ID {:x}", h.alg_id); + + if (h.alg_id_hash != ALG_ID_SHA_1 && h.alg_id_hash != 0) + Rcpp::stop("Unsupported hash algorithm ID {:x}", h.alg_id_hash); + + if (h.key_size != 128) + Rcpp::stop("Key size was {}, expected 128", h.key_size); + + auto sp = enc_info.subspan(sizeof(encryption_info) + ei.header_size); + + if (sp.size() < sizeof(uint32_t)) + Rcpp::stop("Malformed EncryptionInfo"); + + auto salt_size = *(uint32_t*)sp.data(); + sp = sp.subspan(sizeof(uint32_t)); + + if (sp.size() < salt_size) + Rcpp::stop("Malformed EncryptionInfo"); + + auto salt = sp.subspan(0, salt_size); + sp = sp.subspan(salt_size); + + if (sp.size() < 16) + Rcpp::stop("Malformed EncryptionInfo"); + + auto encrypted_verifier = sp.subspan(0, 16); + sp = sp.subspan(16); + + if (sp.size() < sizeof(uint32_t)) + Rcpp::stop("Malformed EncryptionInfo"); + + // skip verifier_hash_size + sp = sp.subspan(sizeof(uint32_t)); + + if (sp.size() < 32) + Rcpp::stop("Malformed EncryptionInfo"); + + auto encrypted_verifier_hash = sp.subspan(0, 32); + + check_password(password, salt, encrypted_verifier, encrypted_verifier_hash); // throws if wrong + + memcpy(this->salt.data(), salt.data(), this->salt.size()); +} + +vector cfbf::decrypt44(span enc_package) { + uint32_t segment_no = 0; + vector ret; + + static const size_t SEGMENT_LENGTH = 0x1000; + + ret.resize(enc_package.size()); + auto ptr = ret.data(); + + while (true) { + array h; + AES_ctx ctx; + + auto seg = enc_package.subspan(0, min(SEGMENT_LENGTH, enc_package.size())); + + memcpy(ptr, seg.data(), seg.size()); + + if (hashalgo == hash_algorithm::sha512) { + sha512_state ctx; + + sha_init(ctx); + sha_process(ctx, salt.data(), (uint32_t)salt.size()); + sha_process(ctx, &segment_no, sizeof(segment_no)); + sha_done(ctx, h.data()); + } else { + SHA1_CTX ctx; + + ctx.update(salt); + ctx.update(span((uint8_t*)&segment_no, sizeof(segment_no))); + + ctx.finalize(h); + } + + if (key_size == 32) { + AES256_init_ctx_iv(&ctx, key.data(), h.data()); + AES256_CBC_decrypt_buffer(&ctx, ptr, seg.size()); + } else { + AES128_init_ctx_iv(&ctx, key.data(), h.data()); + AES128_CBC_decrypt_buffer(&ctx, ptr, seg.size()); + } + + if (enc_package.size() == seg.size()) + break; + + enc_package = enc_package.subspan(seg.size()); + segment_no++; + ptr += seg.size(); + } + + return ret; +} + +vector cfbf::decrypt(span enc_package) { + if (enc_package.size() < sizeof(uint64_t)) + Rcpp::stop("EncryptedPackage was {} bytes, expected at least {}", enc_package.size(), sizeof(uint64_t)); + + auto size = *(uint64_t*)enc_package.data(); + + enc_package = enc_package.subspan(sizeof(uint64_t)); + + if (enc_package.size() < size) + Rcpp::stop("EncryptedPackage was {} bytes, expected at least {}", enc_package.size() + sizeof(uint64_t), size + sizeof(uint64_t)); + + if (agile_enc) + return decrypt44(enc_package); + + AES_ctx ctx; + auto buf = enc_package; + + AES128_init_ctx(&ctx, key.data()); + + while (!buf.empty()) { + AES128_ECB_decrypt(&ctx, buf.data()); + + buf = buf.subspan(16); + } + + vector ret; + + ret.assign(enc_package.begin(), enc_package.end()); + + return ret; +} diff --git a/src/xlcpp/cfbf.h b/src/xlcpp/cfbf.h new file mode 100644 index 000000000..732be30c9 --- /dev/null +++ b/src/xlcpp/cfbf.h @@ -0,0 +1,77 @@ +#pragma once + +#include "mmap.h" +#include +#include +#include +#include +#include +#include +#include +#include + +static const uint64_t CFBF_SIGNATURE = 0xe11ab1a1e011cfd0; + +class _formatted_error : public std::exception { +public: + template + _formatted_error(T&& s, Args&&... args) { + msg = fmt::format(s, std::forward(args)...); + } + + const char* what() const noexcept { + return msg.c_str(); + } + +private: + std::string msg; +}; + +#define formatted_error(s, ...) _formatted_error(FMT_COMPILE(s), ##__VA_ARGS__) + +class cfbf; +struct dirent; + +class cfbf_entry { +public: + cfbf_entry(cfbf& file, const dirent& de, std::string_view name); + size_t read(std::span buf, uint64_t off) const; + size_t get_size() const; + + cfbf& file; + const dirent& de; + std::string name; +}; + +enum class hash_algorithm { + sha1, + sha512 +}; + +class cfbf { +public: + cfbf(std::span s); + uint32_t next_sector(uint32_t sector) const; + uint32_t next_mini_sector(uint32_t sector) const; + void parse_enc_info(std::span enc_info, std::u16string_view password); + void parse_enc_info_44(std::span enc_info, std::u16string_view password); + std::vector decrypt(std::span enc_package); + + std::vector entries; + std::span s; + +private: + void add_entry(std::string_view path, uint32_t num, bool ignore_right); + void check_password(std::u16string_view password, std::span salt, + std::span encrypted_verifier, + std::span encrypted_verifier_hash); + const dirent& find_dirent(uint32_t num); + std::vector decrypt44(std::span enc_package); + + std::unique_ptr m; + std::array key; + unsigned int key_size; + std::array salt; + bool agile_enc = false; + enum hash_algorithm hashalgo; +}; diff --git a/src/xlcpp/mmap.cpp b/src/xlcpp/mmap.cpp new file mode 100644 index 000000000..d2c609c3f --- /dev/null +++ b/src/xlcpp/mmap.cpp @@ -0,0 +1,472 @@ +#include "mmap.h" + +#ifndef _WIN32 +#include +#include +#include +#include +#endif + +using namespace std; + +#ifndef _WIN32 +errno_error::errno_error(string_view function, int en) : msg(function) { + msg += " failed ("; + + switch (en) { + case EPERM: + msg += "EPERM"; + break; + case ENOENT: + msg += "ENOENT"; + break; + case ESRCH: + msg += "ESRCH"; + break; + case EINTR: + msg += "EINTR"; + break; + case EIO: + msg += "EIO"; + break; + case ENXIO: + msg += "ENXIO"; + break; + case E2BIG: + msg += "E2BIG"; + break; + case ENOEXEC: + msg += "ENOEXEC"; + break; + case EBADF: + msg += "EBADF"; + break; + case ECHILD: + msg += "ECHILD"; + break; + case EAGAIN: + msg += "EAGAIN"; + break; + case ENOMEM: + msg += "ENOMEM"; + break; + case EACCES: + msg += "EACCES"; + break; + case EFAULT: + msg += "EFAULT"; + break; + case ENOTBLK: + msg += "ENOTBLK"; + break; + case EBUSY: + msg += "EBUSY"; + break; + case EEXIST: + msg += "EEXIST"; + break; + case EXDEV: + msg += "EXDEV"; + break; + case ENODEV: + msg += "ENODEV"; + break; + case ENOTDIR: + msg += "ENOTDIR"; + break; + case EISDIR: + msg += "EISDIR"; + break; + case EINVAL: + msg += "EINVAL"; + break; + case ENFILE: + msg += "ENFILE"; + break; + case EMFILE: + msg += "EMFILE"; + break; + case ENOTTY: + msg += "ENOTTY"; + break; + case ETXTBSY: + msg += "ETXTBSY"; + break; + case EFBIG: + msg += "EFBIG"; + break; + case ENOSPC: + msg += "ENOSPC"; + break; + case ESPIPE: + msg += "ESPIPE"; + break; + case EROFS: + msg += "EROFS"; + break; + case EMLINK: + msg += "EMLINK"; + break; + case EPIPE: + msg += "EPIPE"; + break; + case EDOM: + msg += "EDOM"; + break; + case ERANGE: + msg += "ERANGE"; + break; + case ENAMETOOLONG: + msg += "ENAMETOOLONG"; + break; + case ENOLCK: + msg += "ENOLCK"; + break; + case ENOSYS: + msg += "ENOSYS"; + break; + case ENOTEMPTY: + msg += "ENOTEMPTY"; + break; + case ELOOP: + msg += "ELOOP"; + break; + case ENOMSG: + msg += "ENOMSG"; + break; + case EIDRM: + msg += "EIDRM"; + break; + case ECHRNG: + msg += "ECHRNG"; + break; + case EL2NSYNC: + msg += "EL2NSYNC"; + break; + case EL3HLT: + msg += "EL3HLT"; + break; + case EL3RST: + msg += "EL3RST"; + break; + case ELNRNG: + msg += "ELNRNG"; + break; + case EUNATCH: + msg += "EUNATCH"; + break; + case ENOCSI: + msg += "ENOCSI"; + break; + case EL2HLT: + msg += "EL2HLT"; + break; + case EBADE: + msg += "EBADE"; + break; + case EBADR: + msg += "EBADR"; + break; + case EXFULL: + msg += "EXFULL"; + break; + case ENOANO: + msg += "ENOANO"; + break; + case EBADRQC: + msg += "EBADRQC"; + break; + case EBADSLT: + msg += "EBADSLT"; + break; + case EDEADLOCK: + msg += "EDEADLOCK"; + break; + case EBFONT: + msg += "EBFONT"; + break; + case ENOSTR: + msg += "ENOSTR"; + break; + case ENODATA: + msg += "ENODATA"; + break; + case ETIME: + msg += "ETIME"; + break; + case ENOSR: + msg += "ENOSR"; + break; + case ENONET: + msg += "ENONET"; + break; + case ENOPKG: + msg += "ENOPKG"; + break; + case EREMOTE: + msg += "EREMOTE"; + break; + case ENOLINK: + msg += "ENOLINK"; + break; + case EADV: + msg += "EADV"; + break; + case ESRMNT: + msg += "ESRMNT"; + break; + case ECOMM: + msg += "ECOMM"; + break; + case EPROTO: + msg += "EPROTO"; + break; + case EMULTIHOP: + msg += "EMULTIHOP"; + break; + case EDOTDOT: + msg += "EDOTDOT"; + break; + case EBADMSG: + msg += "EBADMSG"; + break; + case EOVERFLOW: + msg += "EOVERFLOW"; + break; + case ENOTUNIQ: + msg += "ENOTUNIQ"; + break; + case EBADFD: + msg += "EBADFD"; + break; + case EREMCHG: + msg += "EREMCHG"; + break; + case ELIBACC: + msg += "ELIBACC"; + break; + case ELIBBAD: + msg += "ELIBBAD"; + break; + case ELIBSCN: + msg += "ELIBSCN"; + break; + case ELIBMAX: + msg += "ELIBMAX"; + break; + case ELIBEXEC: + msg += "ELIBEXEC"; + break; + case EILSEQ: + msg += "EILSEQ"; + break; + case ERESTART: + msg += "ERESTART"; + break; + case ESTRPIPE: + msg += "ESTRPIPE"; + break; + case EUSERS: + msg += "EUSERS"; + break; + case ENOTSOCK: + msg += "ENOTSOCK"; + break; + case EDESTADDRREQ: + msg += "EDESTADDRREQ"; + break; + case EMSGSIZE: + msg += "EMSGSIZE"; + break; + case EPROTOTYPE: + msg += "EPROTOTYPE"; + break; + case ENOPROTOOPT: + msg += "ENOPROTOOPT"; + break; + case EPROTONOSUPPORT: + msg += "EPROTONOSUPPORT"; + break; + case ESOCKTNOSUPPORT: + msg += "ESOCKTNOSUPPORT"; + break; + case EOPNOTSUPP: + msg += "EOPNOTSUPP"; + break; + case EPFNOSUPPORT: + msg += "EPFNOSUPPORT"; + break; + case EAFNOSUPPORT: + msg += "EAFNOSUPPORT"; + break; + case EADDRINUSE: + msg += "EADDRINUSE"; + break; + case EADDRNOTAVAIL: + msg += "EADDRNOTAVAIL"; + break; + case ENETDOWN: + msg += "ENETDOWN"; + break; + case ENETUNREACH: + msg += "ENETUNREACH"; + break; + case ENETRESET: + msg += "ENETRESET"; + break; + case ECONNABORTED: + msg += "ECONNABORTED"; + break; + case ECONNRESET: + msg += "ECONNRESET"; + break; + case ENOBUFS: + msg += "ENOBUFS"; + break; + case EISCONN: + msg += "EISCONN"; + break; + case ENOTCONN: + msg += "ENOTCONN"; + break; + case ESHUTDOWN: + msg += "ESHUTDOWN"; + break; + case ETOOMANYREFS: + msg += "ETOOMANYREFS"; + break; + case ETIMEDOUT: + msg += "ETIMEDOUT"; + break; + case ECONNREFUSED: + msg += "ECONNREFUSED"; + break; + case EHOSTDOWN: + msg += "EHOSTDOWN"; + break; + case EHOSTUNREACH: + msg += "EHOSTUNREACH"; + break; + case EALREADY: + msg += "EALREADY"; + break; + case EINPROGRESS: + msg += "EINPROGRESS"; + break; + case ESTALE: + msg += "ESTALE"; + break; + case EUCLEAN: + msg += "EUCLEAN"; + break; + case ENOTNAM: + msg += "ENOTNAM"; + break; + case ENAVAIL: + msg += "ENAVAIL"; + break; + case EISNAM: + msg += "EISNAM"; + break; + case EREMOTEIO: + msg += "EREMOTEIO"; + break; + case EDQUOT: + msg += "EDQUOT"; + break; + case ENOMEDIUM: + msg += "ENOMEDIUM"; + break; + case EMEDIUMTYPE: + msg += "EMEDIUMTYPE"; + break; + case ECANCELED: + msg += "ECANCELED"; + break; + case ENOKEY: + msg += "ENOKEY"; + break; + case EKEYEXPIRED: + msg += "EKEYEXPIRED"; + break; + case EKEYREVOKED: + msg += "EKEYREVOKED"; + break; + case EKEYREJECTED: + msg += "EKEYREJECTED"; + break; + case EOWNERDEAD: + msg += "EOWNERDEAD"; + break; + case ENOTRECOVERABLE: + msg += "ENOTRECOVERABLE"; + break; + case ERFKILL: + msg += "ERFKILL"; + break; + case EHWPOISON: + msg += "EHWPOISON"; + break; + default: + msg += to_string(en); + break; + } + + msg += ")"; +} +#endif + +mmap::mmap(fd_t h) { +#ifdef _WIN32 + LARGE_INTEGER fsli; + + if (!GetFileSizeEx(h, &fsli)) + throw last_error("GetFileSizeEx", GetLastError()); + + filesize = fsli.QuadPart; + + mh = CreateFileMappingW(h, nullptr, PAGE_READONLY, 0, 0, nullptr); + if (!mh) + throw last_error("CreateFileMapping", GetLastError()); +#else + struct stat st; + + if (fstat(h, &st) == -1) + throw errno_error("fstat", errno); + + filesize = st.st_size; + + ptr = ::mmap(nullptr, filesize, PROT_READ, MAP_SHARED, h, 0); + + if (ptr == MAP_FAILED) + throw errno_error("mmap", errno); +#endif +} + +mmap::~mmap() { +#ifdef _WIN32 + if (ptr) + UnmapViewOfFile(ptr); + + if (mh) + CloseHandle(mh); + + if (h != INVALID_HANDLE_VALUE) + CloseHandle(h); +#else + munmap(ptr, filesize); +#endif +} + +span mmap::map() { +#ifdef _WIN32 + if (!ptr) { + ptr = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, 0); + + if (!ptr) + throw last_error("MapViewOfFile", GetLastError()); + } +#endif + + return span((const uint8_t*)ptr, filesize); +} diff --git a/src/xlcpp/mmap.h b/src/xlcpp/mmap.h new file mode 100644 index 000000000..9750e6b8a --- /dev/null +++ b/src/xlcpp/mmap.h @@ -0,0 +1,151 @@ +#pragma once + +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include "utf16.h" +using fd_t = HANDLE; +#else +#include +using fd_t = int; +#endif + +#ifdef _WIN32 +class last_error : public std::exception { +public: + last_error(std::string_view function, int le) { + std::string nice_msg; + + { + char16_t* fm; + + if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, + le, 0, reinterpret_cast(&fm), 0, nullptr)) { + try { + std::u16string_view s = fm; + + while (!s.empty() && (s[s.length() - 1] == u'\r' || s[s.length() - 1] == u'\n')) { + s.remove_suffix(1); + } + + nice_msg = utf16_to_utf8(s); + } catch (...) { + LocalFree(fm); + throw; + } + + LocalFree(fm); + } + } + + msg = std::string(function) + " failed (error " + std::to_string(le) + (!nice_msg.empty() ? (", " + nice_msg) : "") + ")."; + } + + const char* what() const noexcept { + return msg.c_str(); + } + +private: + std::string msg; +}; +#endif + +#ifdef _WIN32 + +class handle_closer { +public: + typedef HANDLE pointer; + + void operator()(HANDLE h) { + if (h == INVALID_HANDLE_VALUE) + return; + + CloseHandle(h); + } +}; + +using unique_handle = std::unique_ptr; + +#else + +class unique_handle { +public: + unique_handle() : fd(0) { + } + + explicit unique_handle(int fd) : fd(fd) { + } + + unique_handle(unique_handle&& that) noexcept { + fd = that.fd; + that.fd = 0; + } + + unique_handle(const unique_handle&) = delete; + unique_handle& operator=(const unique_handle&) = delete; + + unique_handle& operator=(unique_handle&& that) noexcept { + if (fd > 0) + close(fd); + + fd = that.fd; + that.fd = 0; + + return *this; + } + + ~unique_handle() { + if (fd <= 0) + return; + + close(fd); + } + + void reset(int new_fd) noexcept { + if (fd > 0) + close(fd); + + fd = new_fd; + } + + int get() const noexcept { + return fd; + } + +private: + int fd; +}; +#endif + +class errno_error : public std::exception { +public: + errno_error(std::string_view function, int en); + + const char* what() const noexcept { + return msg.c_str(); + } + +private: + std::string msg; +}; + +class mmap { +public: + explicit mmap(fd_t h); + ~mmap(); + std::span map(); + + size_t filesize; + +private: +#ifdef _WIN32 + HANDLE h = INVALID_HANDLE_VALUE; + HANDLE mh = INVALID_HANDLE_VALUE; +#endif + void* ptr = nullptr; +}; diff --git a/src/xlcpp/sha1.cpp b/src/xlcpp/sha1.cpp new file mode 100644 index 000000000..cc251480c --- /dev/null +++ b/src/xlcpp/sha1.cpp @@ -0,0 +1,263 @@ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" +A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" +34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#define SHA1HANDSOFF + +#include +#include +#include +#include + +#include "sha1.h" + +using namespace std; + +constexpr void R0(uint32_t v, uint32_t& w, uint32_t x, uint32_t y, uint32_t& z, uint32_t& bl) { + z += (w & (x^y)) ^ y; + + bl = (rotl(bl,24) & 0xff00ff00) | (rotl(bl,8) & 0x00ff00ff); + z += bl; + + z += 0x5a827999; + z += rotl(v, 5); + + w = rotl(w, 30); +} + +constexpr void R1(uint32_t v, uint32_t& w, uint32_t x, uint32_t y, uint32_t& z, uint32_t i, uint32_t* l) { + z += (w & (x ^ y)) ^ y; + + l[i&15] = rotl(l[(i+13)&15] ^ l[(i+8)&15] ^ l[(i+2)&15] ^ l[i&15], 1); + z += l[i&15]; + + z += 0x5a827999; + z += rotl(v, 5); + + w = rotl(w, 30); +} + +constexpr void R2(uint32_t v, uint32_t& w, uint32_t x, uint32_t y, uint32_t& z, uint32_t i, uint32_t* l) { + z += w ^ x ^ y; + + l[i&15] = rotl(l[(i+13)&15] ^ l[(i+8)&15] ^ l[(i+2)&15] ^ l[i&15], 1); + z += l[i&15]; + + z += 0x6ed9eba1; + z += rotl(v, 5); + + w = rotl(w, 30); +} + +constexpr void R3(uint32_t v, uint32_t& w, uint32_t x, uint32_t y, uint32_t& z, uint32_t i, uint32_t* l) { + z += ((w | x) & y) | (w & x); + + l[i&15] = rotl(l[(i+13)&15] ^ l[(i+8)&15] ^ l[(i+2)&15] ^ l[i&15], 1); + z += l[i&15]; + + z += 0x8f1bbcdc; + z += rotl(v, 5); + + w = rotl(w, 30); +} + +constexpr void R4(uint32_t v, uint32_t& w, uint32_t x, uint32_t y, uint32_t& z, uint32_t i, uint32_t* l) { + z += w ^ x ^ y; + + l[i&15] = rotl(l[(i+13)&15] ^ l[(i+8)&15] ^ l[(i+2)&15] ^ l[i&15], 1); + z += l[i&15]; + + z += 0xca62c1d6; + z += rotl(v,5); + + w = rotl(w,30); +} + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +static void SHA1Transform(uint32_t state[5], uint8_t buffer[64]) { + uint32_t a, b, c, d, e; + uint32_t l[16]; + + memcpy(l, buffer, 64); + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, l[0]); + R0(e,a,b,c,d, l[1]); + R0(d,e,a,b,c, l[2]); + R0(c,d,e,a,b, l[3]); + R0(b,c,d,e,a, l[4]); + R0(a,b,c,d,e, l[5]); + R0(e,a,b,c,d, l[6]); + R0(d,e,a,b,c, l[7]); + R0(c,d,e,a,b, l[8]); + R0(b,c,d,e,a, l[9]); + R0(a,b,c,d,e, l[10]); + R0(e,a,b,c,d, l[11]); + R0(d,e,a,b,c, l[12]); + R0(c,d,e,a,b, l[13]); + R0(b,c,d,e,a, l[14]); + R0(a,b,c,d,e, l[15]); + + R1(e,a,b,c,d, 16, l); + R1(d,e,a,b,c, 17, l); + R1(c,d,e,a,b, 18, l); + R1(b,c,d,e,a, 19, l); + + R2(a,b,c,d,e,20, l); + R2(e,a,b,c,d,21, l); + R2(d,e,a,b,c,22, l); + R2(c,d,e,a,b,23, l); + R2(b,c,d,e,a,24, l); + R2(a,b,c,d,e,25, l); + R2(e,a,b,c,d,26, l); + R2(d,e,a,b,c,27, l); + R2(c,d,e,a,b,28, l); + R2(b,c,d,e,a,29, l); + R2(a,b,c,d,e,30, l); + R2(e,a,b,c,d,31, l); + R2(d,e,a,b,c,32, l); + R2(c,d,e,a,b,33, l); + R2(b,c,d,e,a,34, l); + R2(a,b,c,d,e,35, l); + R2(e,a,b,c,d,36, l); + R2(d,e,a,b,c,37, l); + R2(c,d,e,a,b,38, l); + R2(b,c,d,e,a,39, l); + + R3(a,b,c,d,e,40, l); + R3(e,a,b,c,d,41, l); + R3(d,e,a,b,c,42, l); + R3(c,d,e,a,b,43, l); + R3(b,c,d,e,a,44, l); + R3(a,b,c,d,e,45, l); + R3(e,a,b,c,d,46, l); + R3(d,e,a,b,c,47, l); + R3(c,d,e,a,b,48, l); + R3(b,c,d,e,a,49, l); + R3(a,b,c,d,e,50, l); + R3(e,a,b,c,d,51, l); + R3(d,e,a,b,c,52, l); + R3(c,d,e,a,b,53, l); + R3(b,c,d,e,a,54, l); + R3(a,b,c,d,e,55, l); + R3(e,a,b,c,d,56, l); + R3(d,e,a,b,c,57, l); + R3(c,d,e,a,b,58, l); + R3(b,c,d,e,a,59, l); + + R4(a,b,c,d,e,60, l); + R4(e,a,b,c,d,61, l); + R4(d,e,a,b,c,62, l); + R4(c,d,e,a,b,63, l); + R4(b,c,d,e,a,64, l); + R4(a,b,c,d,e,65, l); + R4(e,a,b,c,d,66, l); + R4(d,e,a,b,c,67, l); + R4(c,d,e,a,b,68, l); + R4(b,c,d,e,a,69, l); + R4(a,b,c,d,e,70, l); + R4(e,a,b,c,d,71, l); + R4(d,e,a,b,c,72, l); + R4(c,d,e,a,b,73, l); + R4(b,c,d,e,a,74, l); + R4(a,b,c,d,e,75, l); + R4(e,a,b,c,d,76, l); + R4(d,e,a,b,c,77, l); + R4(c,d,e,a,b,78, l); + R4(b,c,d,e,a,79, l); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; +} + +/* Run your data through this. */ + +void SHA1_CTX::update(std::span data) { + uint32_t i; + + auto j = count[0]; + + count[0] += (uint32_t)(data.size() << 3); + + if (count[0] < j) + count[1]++; + + count[1] += (uint32_t)(data.size() >> 29); + + j = (j >> 3) & 63; + + if (j + data.size() > 63) { + i = 64 - j; + memcpy(&buffer[j], data.data(), i); + SHA1Transform(state, buffer); + for ( ; i + 63 < data.size(); i += 64) { + SHA1Transform(state, (uint8_t*)&data[i]); + } + j = 0; + } else + i = 0; + + memcpy(&buffer[j], &data[i], data.size() - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1_CTX::finalize(span digest) { + unsigned i; + unsigned char finalcount[8]; + unsigned char c; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + + c = 0200; + update(span(&c, 1)); + while ((count[0] & 504) != 448) { + c = 0000; + update(span(&c, 1)); + } + update(span(finalcount, 8)); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } +} + +array sha1(span s) { + array digest; + SHA1_CTX ctx; + + ctx.update(s); + ctx.finalize(digest); + + return digest; +} + diff --git a/src/xlcpp/sha1.h b/src/xlcpp/sha1.h new file mode 100644 index 000000000..9e77d69a3 --- /dev/null +++ b/src/xlcpp/sha1.h @@ -0,0 +1,35 @@ +/* +SHA-1 in C +By Steve Reid +100% Public Domain +*/ + +#pragma once + +#include +#include + +struct SHA1_CTX { + constexpr SHA1_CTX() { + /* SHA1 initialization constants */ + state[0] = 0x67452301; + state[1] = 0xEFCDAB89; + state[2] = 0x98BADCFE; + state[3] = 0x10325476; + state[4] = 0xC3D2E1F0; + count[0] = count[1] = 0; + + for (unsigned int i = 0; i < sizeof(buffer); i++) { + buffer[i] = 0; + } + } + + void update(std::span data); + void finalize(std::span digest); + + uint32_t state[5]; + uint32_t count[2]; + unsigned char buffer[64]; +}; + +std::array sha1(std::span s); diff --git a/src/xlcpp/sha512.cpp b/src/xlcpp/sha512.cpp new file mode 100644 index 000000000..89e6f270f --- /dev/null +++ b/src/xlcpp/sha512.cpp @@ -0,0 +1,174 @@ +// SHA-512. Adapted from LibTomCrypt. This code is Public Domain +#include "sha512.h" +#include + +static const uint64_t K[80] = +{ + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, + 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, + 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, + 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, + 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, + 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, + 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, + 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, + 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +static uint32_t min(uint32_t x, uint32_t y) +{ + return x < y ? x : y; +} + +static void store64(uint64_t x, unsigned char* y) +{ + for(int i = 0; i != 8; ++i) + y[i] = (x >> ((7-i) * 8)) & 255; +} + +static uint64_t load64(const unsigned char* y) +{ + uint64_t res = 0; + for(int i = 0; i != 8; ++i) + res |= uint64_t(y[i]) << ((7-i) * 8); + return res; +} + +static uint64_t Ch(uint64_t x, uint64_t y, uint64_t z) { return z ^ (x & (y ^ z)); } +static uint64_t Maj(uint64_t x, uint64_t y, uint64_t z) { return ((x | y) & z) | (x & y); } +static uint64_t Rot(uint64_t x, uint64_t n) { return (x >> (n & 63)) | (x << (64 - (n & 63))); } +static uint64_t Sh(uint64_t x, uint64_t n) { return x >> n; } +static uint64_t Sigma0(uint64_t x) { return Rot(x, 28) ^ Rot(x, 34) ^ Rot(x, 39); } +static uint64_t Sigma1(uint64_t x) { return Rot(x, 14) ^ Rot(x, 18) ^ Rot(x, 41); } +static uint64_t Gamma0(uint64_t x) { return Rot(x, 1) ^ Rot(x, 8) ^ Sh(x, 7); } +static uint64_t Gamma1(uint64_t x) { return Rot(x, 19) ^ Rot(x, 61) ^ Sh(x, 6); } + +static void sha_compress(sha512_state& md, const unsigned char *buf) +{ + uint64_t S[8], W[80], t0, t1; + + // Copy state into S + for(int i = 0; i < 8; i++) + S[i] = md.state[i]; + + // Copy the state into 1024-bits into W[0..15] + for(int i = 0; i < 16; i++) + W[i] = load64(buf + (8*i)); + + // Fill W[16..79] + for(int i = 16; i < 80; i++) + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + + // Compress + auto RND = [&](uint64_t a, uint64_t b, uint64_t c, uint64_t& d, uint64_t e, uint64_t f, uint64_t g, uint64_t& h, uint64_t i) + { + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; + t1 = Sigma0(a) + Maj(a, b, c); + d += t0; + h = t0 + t1; + }; + + for(int i = 0; i < 80; i += 8) + { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); + } + + // Feedback + for(int i = 0; i < 8; i++) + md.state[i] = md.state[i] + S[i]; +} + +// Public interface + +void sha_init(sha512_state& md) +{ + md.curlen = 0; + md.length = 0; + md.state[0] = 0x6a09e667f3bcc908ULL; + md.state[1] = 0xbb67ae8584caa73bULL; + md.state[2] = 0x3c6ef372fe94f82bULL; + md.state[3] = 0xa54ff53a5f1d36f1ULL; + md.state[4] = 0x510e527fade682d1ULL; + md.state[5] = 0x9b05688c2b3e6c1fULL; + md.state[6] = 0x1f83d9abfb41bd6bULL; + md.state[7] = 0x5be0cd19137e2179ULL; +} + +void sha_process(sha512_state& md, const void* src, uint32_t inlen) +{ + const uint32_t block_size = sizeof(sha512_state::buf); + auto in = static_cast(src); + + while(inlen > 0) + { + if(md.curlen == 0 && inlen >= block_size) + { + sha_compress(md, in); + md.length += block_size * 8; + in += block_size; + inlen -= block_size; + } + else + { + uint32_t n = min(inlen, (block_size - md.curlen)); + memcpy(md.buf + md.curlen, in, n); + md.curlen += n; + in += n; + inlen -= n; + + if(md.curlen == block_size) + { + sha_compress(md, md.buf); + md.length += 8*block_size; + md.curlen = 0; + } + } + } +} + +void sha_done(sha512_state& md, void *out) +{ + // Increase the length of the message + md.length += md.curlen * 8ULL; + + // Append the '1' bit + md.buf[md.curlen++] = static_cast(0x80); + + // If the length is currently above 112 bytes we append zeros then compress. + // Then we can fall back to padding zeros and length encoding like normal. + if(md.curlen > 112) + { + while(md.curlen < 128) + md.buf[md.curlen++] = 0; + sha_compress(md, md.buf); + md.curlen = 0; + } + + // Pad upto 120 bytes of zeroes + // note: that from 112 to 120 is the 64 MSB of the length. We assume that + // you won't hash 2^64 bits of data... :-) + while(md.curlen < 120) + md.buf[md.curlen++] = 0; + + // Store length + store64(md.length, md.buf+120); + sha_compress(md, md.buf); + + // Copy output + for(int i = 0; i < 8; i++) + store64(md.state[i], static_cast(out)+(8*i)); +} diff --git a/src/xlcpp/sha512.h b/src/xlcpp/sha512.h new file mode 100644 index 000000000..0ba62cb19 --- /dev/null +++ b/src/xlcpp/sha512.h @@ -0,0 +1,16 @@ +// SHA-512. Adapted from LibTomCrypt. This code is Public Domain +#pragma once + +#include + +struct sha512_state +{ + uint64_t length; + uint64_t state[8]; + uint32_t curlen; + unsigned char buf[128]; +}; + +void sha_init(sha512_state& md); +void sha_process(sha512_state& md, const void* in, uint32_t inlen); +void sha_done(sha512_state& md, void* out); diff --git a/src/xlcpp/utf16.h b/src/xlcpp/utf16.h new file mode 100644 index 000000000..8c3c03a95 --- /dev/null +++ b/src/xlcpp/utf16.h @@ -0,0 +1,346 @@ +#pragma once + +#include + +template +requires (std::is_same_v || (sizeof(wchar_t) == 2 && std::is_same_v)) +static constexpr size_t utf16_to_utf8_len(std::basic_string_view sv) noexcept { + size_t ret = 0; + + while (!sv.empty()) { + if (sv[0] < 0x80) + ret++; + else if (sv[0] < 0x800) + ret += 2; + else if (sv[0] < 0xd800) + ret += 3; + else if (sv[0] < 0xdc00) { + if (sv.length() < 2 || (sv[1] & 0xdc00) != 0xdc00) { + ret += 3; + sv = sv.substr(1); + continue; + } + + ret += 4; + sv = sv.substr(1); + } else + ret += 3; + + sv = sv.substr(1); + } + + return ret; +} + +template +requires (std::is_same_v || (sizeof(wchar_t) == 2 && std::is_same_v)) +static constexpr size_t utf16_to_utf8_len(const T (&str)[N]) noexcept { + return utf16_to_utf8_len(std::basic_string_view{str, N - 1}); +} + +template +requires (std::is_same_v || (sizeof(wchar_t) == 2 && std::is_same_v)) && +((std::ranges::output_range && std::is_same_v, char>) || +(std::ranges::output_range && std::is_same_v, char8_t>)) +static constexpr void utf16_to_utf8_range(std::basic_string_view sv, U& t) noexcept { + auto ptr = t.begin(); + + if (ptr == t.end()) + return; + + while (!sv.empty()) { + if (sv[0] < 0x80) { + *ptr = (uint8_t)sv[0]; + ptr++; + + if (ptr == t.end()) + return; + } else if (sv[0] < 0x800) { + *ptr = (uint8_t)(0xc0 | (sv[0] >> 6)); + ptr++; + + if (ptr == t.end()) + return; + + *ptr = (uint8_t)(0x80 | (sv[0] & 0x3f)); + ptr++; + + if (ptr == t.end()) + return; + } else if (sv[0] < 0xd800) { + *ptr = (uint8_t)(0xe0 | (sv[0] >> 12)); + ptr++; + + if (ptr == t.end()) + return; + + *ptr = (uint8_t)(0x80 | ((sv[0] >> 6) & 0x3f)); + ptr++; + + if (ptr == t.end()) + return; + + *ptr = (uint8_t)(0x80 | (sv[0] & 0x3f)); + ptr++; + + if (ptr == t.end()) + return; + } else if (sv[0] < 0xdc00) { + if (sv.length() < 2 || (sv[1] & 0xdc00) != 0xdc00) { + *ptr = (uint8_t)0xef; + ptr++; + + if (ptr == t.end()) + return; + + *ptr = (uint8_t)0xbf; + ptr++; + + if (ptr == t.end()) + return; + + *ptr = (uint8_t)0xbd; + ptr++; + + if (ptr == t.end()) + return; + + sv = sv.substr(1); + continue; + } + + char32_t cp = 0x10000 | ((sv[0] & ~0xd800) << 10) | (sv[1] & ~0xdc00); + + *ptr = (uint8_t)(0xf0 | (cp >> 18)); + ptr++; + + if (ptr == t.end()) + return; + + *ptr = (uint8_t)(0x80 | ((cp >> 12) & 0x3f)); + ptr++; + + if (ptr == t.end()) + return; + + *ptr = (uint8_t)(0x80 | ((cp >> 6) & 0x3f)); + ptr++; + + if (ptr == t.end()) + return; + + *ptr = (uint8_t)(0x80 | (cp & 0x3f)); + ptr++; + + if (ptr == t.end()) + return; + + sv = sv.substr(1); + } else if (sv[0] < 0xe000) { + *ptr = (uint8_t)0xef; + ptr++; + + if (ptr == t.end()) + return; + + *ptr = (uint8_t)0xbf; + ptr++; + + if (ptr == t.end()) + return; + + *ptr = (uint8_t)0xbd; + ptr++; + + if (ptr == t.end()) + return; + } else { + *ptr = (uint8_t)(0xe0 | (sv[0] >> 12)); + ptr++; + + if (ptr == t.end()) + return; + + *ptr = (uint8_t)(0x80 | ((sv[0] >> 6) & 0x3f)); + ptr++; + + if (ptr == t.end()) + return; + + *ptr = (uint8_t)(0x80 | (sv[0] & 0x3f)); + ptr++; + + if (ptr == t.end()) + return; + } + + sv = sv.substr(1); + } +} + +static std::string __inline utf16_to_utf8(std::u16string_view sv) { + if (sv.empty()) + return ""; + + std::string ret(utf16_to_utf8_len(sv), 0); + + utf16_to_utf8_range(sv, ret); + + return ret; +} + +static constexpr size_t utf8_to_utf16_len(std::string_view sv) noexcept { + size_t ret = 0; + + while (!sv.empty()) { + if ((uint8_t)sv[0] < 0x80) { + ret++; + sv = sv.substr(1); + } else if (((uint8_t)sv[0] & 0xe0) == 0xc0 && (uint8_t)sv.length() >= 2 && ((uint8_t)sv[1] & 0xc0) == 0x80) { + ret++; + sv = sv.substr(2); + } else if (((uint8_t)sv[0] & 0xf0) == 0xe0 && (uint8_t)sv.length() >= 3 && ((uint8_t)sv[1] & 0xc0) == 0x80 && ((uint8_t)sv[2] & 0xc0) == 0x80) { + ret++; + sv = sv.substr(3); + } else if (((uint8_t)sv[0] & 0xf8) == 0xf0 && (uint8_t)sv.length() >= 4 && ((uint8_t)sv[1] & 0xc0) == 0x80 && ((uint8_t)sv[2] & 0xc0) == 0x80 && ((uint8_t)sv[3] & 0xc0) == 0x80) { + char32_t cp = (char32_t)(((uint8_t)sv[0] & 0x7) << 18) | (char32_t)(((uint8_t)sv[1] & 0x3f) << 12) | (char32_t)(((uint8_t)sv[2] & 0x3f) << 6) | (char32_t)((uint8_t)sv[3] & 0x3f); + + if (cp > 0x10ffff) { + ret++; + sv = sv.substr(4); + continue; + } + + ret += 2; + sv = sv.substr(4); + } else { + ret++; + sv = sv.substr(1); + } + } + + return ret; +} + +static constexpr size_t utf8_to_utf16_len(std::u8string_view sv) noexcept { + return utf8_to_utf16_len(std::string_view(std::bit_cast(sv.data()), sv.length())); +} + +template +requires (std::ranges::output_range && std::is_same_v, char16_t>) || + (sizeof(wchar_t) == 2 && std::ranges::output_range && std::is_same_v, wchar_t>) +static constexpr void utf8_to_utf16_range(std::string_view sv, T& t) noexcept { + auto ptr = t.begin(); + + if (ptr == t.end()) + return; + + while (!sv.empty()) { + if ((uint8_t)sv[0] < 0x80) { + *ptr = (uint8_t)sv[0]; + ptr++; + + if (ptr == t.end()) + return; + + sv = sv.substr(1); + } else if (((uint8_t)sv[0] & 0xe0) == 0xc0 && (uint8_t)sv.length() >= 2 && ((uint8_t)sv[1] & 0xc0) == 0x80) { + char16_t cp = (char16_t)(((uint8_t)sv[0] & 0x1f) << 6) | (char16_t)((uint8_t)sv[1] & 0x3f); + + *ptr = cp; + ptr++; + + if (ptr == t.end()) + return; + + sv = sv.substr(2); + } else if (((uint8_t)sv[0] & 0xf0) == 0xe0 && (uint8_t)sv.length() >= 3 && ((uint8_t)sv[1] & 0xc0) == 0x80 && ((uint8_t)sv[2] & 0xc0) == 0x80) { + char16_t cp = (char16_t)(((uint8_t)sv[0] & 0xf) << 12) | (char16_t)(((uint8_t)sv[1] & 0x3f) << 6) | (char16_t)((uint8_t)sv[2] & 0x3f); + + if (cp >= 0xd800 && cp <= 0xdfff) { + *ptr = 0xfffd; + ptr++; + + if (ptr == t.end()) + return; + + sv = sv.substr(3); + continue; + } + + *ptr = cp; + ptr++; + + if (ptr == t.end()) + return; + + sv = sv.substr(3); + } else if (((uint8_t)sv[0] & 0xf8) == 0xf0 && (uint8_t)sv.length() >= 4 && ((uint8_t)sv[1] & 0xc0) == 0x80 && ((uint8_t)sv[2] & 0xc0) == 0x80 && ((uint8_t)sv[3] & 0xc0) == 0x80) { + char32_t cp = (char32_t)(((uint8_t)sv[0] & 0x7) << 18) | (char32_t)(((uint8_t)sv[1] & 0x3f) << 12) | (char32_t)(((uint8_t)sv[2] & 0x3f) << 6) | (char32_t)((uint8_t)sv[3] & 0x3f); + + if (cp > 0x10ffff) { + *ptr = 0xfffd; + ptr++; + + if (ptr == t.end()) + return; + + sv = sv.substr(4); + continue; + } + + cp -= 0x10000; + + *ptr = (char16_t)(0xd800 | (cp >> 10)); + ptr++; + + if (ptr == t.end()) + return; + + *ptr = (char16_t)(0xdc00 | (cp & 0x3ff)); + ptr++; + + if (ptr == t.end()) + return; + + sv = sv.substr(4); + } else { + *ptr = 0xfffd; + ptr++; + + if (ptr == t.end()) + return; + + sv = sv.substr(1); + } + } +} + +template +requires (std::ranges::output_range && std::is_same_v, char16_t>) || + (sizeof(wchar_t) == 2 && std::ranges::output_range && std::is_same_v, wchar_t>) +static constexpr void utf8_to_utf16_range(std::u8string_view sv, T& t) noexcept { + utf8_to_utf16_range(std::string_view((char*)sv.data(), sv.length()), t); +} + +static __inline std::u16string utf8_to_utf16(std::string_view sv) { + if (sv.empty()) + return u""; + + std::u16string ret(utf8_to_utf16_len(sv), 0); + + utf8_to_utf16_range(sv, ret); + + return ret; +} + +static __inline std::u16string utf8_to_utf16(std::u8string_view sv) { + if (sv.empty()) + return u""; + + std::u16string ret(utf8_to_utf16_len(sv), 0); + + utf8_to_utf16_range(sv, ret); + + return ret; +} diff --git a/src/xlcpp/xlcpp-pimpl.h b/src/xlcpp/xlcpp-pimpl.h new file mode 100644 index 000000000..f3614fcd4 --- /dev/null +++ b/src/xlcpp/xlcpp-pimpl.h @@ -0,0 +1,364 @@ +#pragma once + +#include "xlcpp.h" +#include "mmap.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace xlcpp { + +struct shared_string { + unsigned int num; +}; + +typedef struct { + std::string content_type; + std::string data; +} file; + +class font { +public: + font(std::string_view font_name, unsigned int font_size, bool bold) : font_name(font_name), font_size(font_size), bold(bold) { } + + std::string font_name; + unsigned int font_size; + bool bold; +}; + +class font_hash { +public: + size_t operator()(const font& f) const { + return std::hash{}(f.font_name) | + (std::hash{}(f.font_size) << 1) | + (std::hash{}(f.bold) << 2); + } +}; + +bool operator==(const font& lhs, const font& rhs) noexcept; + +class style { +public: + style(std::string_view number_format, std::string_view font, unsigned int font_size, bool bold = false) : + number_format(number_format), font(font, font_size, bold) { } + + void set_font(std::string_view font_name, unsigned int font_size, bool bold); + void set_number_format(std::string_view fmt); + + std::string number_format; + xlcpp::font font; + + mutable unsigned int num; + mutable unsigned int number_format_num; +}; + +class style_hash { +public: + size_t operator()(const style& s) const { + return std::hash{}(s.number_format) | + (font_hash{}(s.font) << 1); + } +}; + +bool operator==(const style& lhs, const style& rhs) noexcept; + +class workbook_pimpl { +public: + workbook_pimpl() = default; + workbook_pimpl(const std::filesystem::path& fn, std::string_view password, std::string_view outfile); + workbook_pimpl(std::span sv, std::string_view password, std::string_view outfile); + sheet& add_sheet(std::string_view name, bool visible); + void save(const std::filesystem::path& fn) const; + std::string data() const; + + void write_workbook_xml(struct archive* a) const; + void write_content_types_xml(struct archive* a) const; + void write_rels(struct archive* a) const; + void write_workbook_rels(struct archive* a) const; + shared_string get_shared_string(std::string_view s); + void write_shared_strings(struct archive* a) const; + void write_styles(struct archive* a) const; + void write_archive(struct archive* a) const; + la_ssize_t write_callback(struct archive* a, const void* buffer, size_t length) const; + void parse_workbook(std::string_view fn, std::string_view data, + const std::unordered_map& files); + void parse_workbook_binary(std::string_view fn, std::span data, + const std::unordered_map& files); + void load_sheet(std::string_view name, std::string_view data, bool visible); + void load_sheet_binary(std::string_view name, std::span data, bool visible); + void load_shared_strings2(std::string_view sv); + void load_shared_strings_binary(std::span data); + void load_shared_strings(const std::unordered_map& files); + void load_styles(const std::unordered_map& files); + void load_styles2(std::string_view sv); + void load_styles_binary(std::span data); + std::string find_number_format(unsigned int num); + void load_archive(struct archive* a); + +#ifdef _WIN32 + void rename(const std::filesystem::path& fn) const; +#endif + + template + const style* find_style(Args&&... args) { + auto ret = styles.emplace(args...); + + if (ret.second) + ret.first->num = (unsigned int)(styles.size() - 1); + + return &(*ret.first); + } + + std::list sheets; + std::map> shared_strings; + std::vector shared_strings2; + std::unordered_set styles; + std::unordered_map number_formats; + std::vector> cell_styles; + bool date1904 = false; + + mutable std::string buf; + +#ifdef _WIN32 + unique_handle h; + HANDLE h2; + uint8_t readbuf[1048576]; +#endif + +private: + void load_from_memory(std::span sv, std::string_view password, std::string_view outfile); +}; + +class sheet_pimpl { +public: + sheet_pimpl(workbook_pimpl& wb, std::string_view name, unsigned int num, bool visible) : parent(wb), name(name), num(num), visible(visible) { } + + void write(struct archive* a) const; + std::string xml() const; + row& add_row(); + + workbook_pimpl& parent; + std::string name; + unsigned int num; + bool visible; + std::list rows; +}; + +class row_pimpl { +public: + row_pimpl(sheet_pimpl& s, unsigned int num) : parent(s), num(num) { } + + template + cell& add_cell(const T& val) { + return *cells.emplace(cells.end(), *this, cells.size() + 1, val); + } + + sheet_pimpl& parent; + unsigned int num; + std::list cells; +}; + +class cell_pimpl { +public: + template + cell_pimpl(row_pimpl& r, unsigned int num, const T& t); + + cell_pimpl(row_pimpl& r, unsigned int num, std::string_view t); + cell_pimpl(row_pimpl& r, unsigned int num, const std::chrono::system_clock::time_point& val) : cell_pimpl(r, num, datetime{val}) { } + + void set_number_format(std::string_view fmt); + void set_font(std::string_view name, unsigned int size, bool bold = false); + + row_pimpl& parent; + + const style* sty; + + unsigned int num; + std::variant val; + std::string number_format; +}; + +}; + +class xml_writer { +public: + std::string dump() const; + void start_document(); + void start_element(std::string_view tag, const std::unordered_map& namespaces = {}); + void end_element(); + void text(std::string_view s); + void attribute(std::string_view name, std::string_view value); + +private: + std::string buf; + std::stack tags; + bool empty_tag; +}; + +enum class xml_node { + unknown, + text, + whitespace, + element, + end_element, + processing_instruction, + comment, + cdata +}; + +template<> +struct fmt::formatter { + constexpr auto parse(format_parse_context& ctx) { + auto it = ctx.begin(); + + if (it != ctx.end() && *it != '}') + throw format_error("invalid format"); + + return it; + } + + template + auto format(enum xml_node n, format_context& ctx) const { + switch (n) { + case xml_node::unknown: + return fmt::format_to(ctx.out(), "unknown"); + case xml_node::text: + return fmt::format_to(ctx.out(), "text"); + case xml_node::whitespace: + return fmt::format_to(ctx.out(), "whitespace"); + case xml_node::element: + return fmt::format_to(ctx.out(), "element"); + case xml_node::end_element: + return fmt::format_to(ctx.out(), "end_element"); + case xml_node::processing_instruction: + return fmt::format_to(ctx.out(), "processing_instruction"); + case xml_node::comment: + return fmt::format_to(ctx.out(), "comment"); + case xml_node::cdata: + return fmt::format_to(ctx.out(), "cdata"); + default: + return fmt::format_to(ctx.out(), "{:x}", (unsigned int)n); + } + } +}; + +class xml_enc_string_view { +public: + xml_enc_string_view() { } + xml_enc_string_view(std::string_view sv) : sv(sv) { } + + bool empty() const noexcept { + return sv.empty(); + } + + std::string decode() const; + bool cmp(std::string_view str) const; + +private: + std::string_view sv; +}; + +using ns_list = std::vector>; + +class xml_reader { +public: + xml_reader(std::string_view sv) : sv(sv) { } + bool read(); + enum xml_node node_type() const; + bool is_empty() const; + void attributes_loop_raw(const std::function& func) const; + std::optional get_attribute(std::string_view name, std::string_view ns = "") const; + xml_enc_string_view namespace_uri_raw() const; + std::string_view name() const; + std::string_view local_name() const; + std::string value() const; + +private: + std::string_view sv, node; + enum xml_node type = xml_node::unknown; + bool empty_tag; + std::vector namespaces; +}; + +class archive_read_closer { +public: + typedef archive* pointer; + + void operator()(archive* a) { + archive_read_free(a); + } +}; + +using archive_read_t = std::unique_ptr; + +class archive_write_closer { +public: + typedef archive* pointer; + + void operator()(archive* a) { + archive_write_free(a); + } +}; + +using archive_write_t = std::unique_ptr; + + +static constexpr std::chrono::year_month_day number_to_date(unsigned int num, bool date1904) noexcept { + unsigned int J = num + 2415019; + unsigned int f, e, g, h; + unsigned int day, month; + int year; + + if (date1904) + J += 1462; + else if (num < 61) // Excel's 29/2/1900 bug + J++; + + f = J; + f *= 4; + f += 274277; + f /= 146097; + f *= 3; + f /= 4; + f += J; + f += 1363; + + e = (f * 4) + 3; + + g = e % 1461; + g /= 4; + + h = (5 * g) + 2; + + day = h % 153; + day /= 5; + day++; + + month = h; + month /= 153; + month += 2; + month %= 12; + month++; + + year = 14 - month; + year /= 12; + year -= 4716; + year += e / 1461; + + return std::chrono::year_month_day{std::chrono::year{year}, std::chrono::month{month}, std::chrono::day{day}}; +} + +// xlcpp.cpp +bool is_date(std::string_view sv); +bool is_time(std::string_view sv); +std::unordered_map read_relationships(std::string_view fn, const std::unordered_map& files); diff --git a/src/xlcpp/xlcpp.cpp b/src/xlcpp/xlcpp.cpp new file mode 100644 index 000000000..d873cb5e7 --- /dev/null +++ b/src/xlcpp/xlcpp.cpp @@ -0,0 +1,2070 @@ +#include "openxlsx2.h" +#include +#include + +#include "xlcpp.h" +#include "xlcpp-pimpl.h" +#include "mmap.h" +#include "cfbf.h" +#include "utf16.h" +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + +#define FMT_HEADER_ONLY +#include +#include + +#define BLOCK_SIZE 20480 + +using namespace std; + +static const string NS_SPREADSHEET = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"; +static const string NS_SPREADSHEET_STRICT = "http://purl.oclc.org/ooxml/spreadsheetml/main"; +static const string NS_RELATIONSHIPS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; +static const string NS_RELATIONSHIPS_STRICT = "http://purl.oclc.org/ooxml/officeDocument/relationships"; +static const string NS_PACKAGE_RELATIONSHIPS = "http://schemas.openxmlformats.org/package/2006/relationships"; +static const string NS_CONTENT_TYPES = "http://schemas.openxmlformats.org/package/2006/content-types"; + +#define NUMFMT_OFFSET 165 + +static const array builtin_styles = { + pair{ 0, "General" }, + pair{ 1, "0" }, + pair{ 2, "0.00" }, + pair{ 3, "#,##0" }, + pair{ 4, "#,##0.00" }, + pair{ 9, "0%" }, + pair{ 10, "0.00%" }, + pair{ 11, "0.00E+00" }, + pair{ 12, "# ?/?" }, + pair{ 13, "# \?\?/??" }, + pair{ 14, "mm-dd-yy" }, + pair{ 15, "d-mmm-yy" }, + pair{ 16, "d-mmm" }, + pair{ 17, "mmm-yy" }, + pair{ 18, "h:mm AM/PM" }, + pair{ 19, "h:mm:ss AM/PM" }, + pair{ 20, "h:mm" }, + pair{ 21, "h:mm:ss" }, + pair{ 22, "m/d/yy h:mm" }, + pair{ 37, "#,##0 ;(#,##0)" }, + pair{ 38, "#,##0 ;[Red](#,##0)" }, + pair{ 39, "#,##0.00;(#,##0.00)" }, + pair{ 40, "#,##0.00;[Red](#,##0.00)" }, + pair{ 45, "mm:ss" }, + pair{ 46, "[h]:mm:ss" }, + pair{ 47, "mmss.0" }, + pair{ 48, "##0.0E+0" }, + pair{ 49, "@" }, +}; + +bool is_date(string_view sv) { + if (sv == "General") + return false; + + string s; + + s.reserve(sv.length()); + + for (auto c : sv) { + if (c >= 'a' && c <= 'z') { + if (s.empty() || s.back() != c) + s += c; + } else if (c >= 'A' && c <= 'Z') { + if (s.empty() || s.back() != c - 'A' + 'a') + s += c - 'A' + 'a'; + } + } + + static const char* patterns[] = { + "dmy", + "ymd", + "mdy", + "my" + }; + + for (const auto& p : patterns) { + if (s.find(p) != string::npos) + return true; + } + + return false; +} + +bool is_time(string_view sv) { + if (sv == "General") + return false; + + string s; + + s.reserve(sv.length()); + + for (auto c : sv) { + if (c >= 'a' && c <= 'z') { + if (s.empty() || s.back() != c) + s += c; + } else if (c >= 'A' && c <= 'Z') { + if (s.empty() || s.back() != c - 'A' + 'a') + s += c - 'A' + 'a'; + } + } + + // FIXME - "h AM/PM" etc. + + return s.find("hm") != string::npos; +} + +static string try_decode(const optional& sv) { + if (!sv) + return ""; + + return sv.value().decode(); +} + +unordered_map read_relationships(string_view fn, const unordered_map& files) { + filesystem::path p = fn; + unordered_map rels; + + p.remove_filename(); + p /= "_rels"; + p /= filesystem::path(fn).filename().string() + ".rels"; + + auto ps = p.string(); + + for (auto& c : ps) { + if (c == '\\') + c = '/'; + } + + if (files.count(ps) == 0) + Rcpp::stop("File {} not found.", ps); + + xml_reader r(files.at(ps).data); + unsigned int depth = 0; + + while (r.read()) { + unsigned int next_depth; + + if (r.node_type() == xml_node::element && !r.is_empty()) + next_depth = depth + 1; + else if (r.node_type() == xml_node::end_element) + next_depth = depth - 1; + else + next_depth = depth; + + if (r.node_type() == xml_node::element) { + if (depth == 0) { + if (r.local_name() != "Relationships" || !r.namespace_uri_raw().cmp(NS_PACKAGE_RELATIONSHIPS)) { + Rcpp::stop("Root tag was {{{}}}{}, expected {{{}}}Relationships.", + r.namespace_uri_raw().decode(), r.local_name(), NS_PACKAGE_RELATIONSHIPS); + } + } else if (depth == 1) { + if (r.local_name() == "Relationship" && r.namespace_uri_raw().cmp(NS_PACKAGE_RELATIONSHIPS)) { + auto id = try_decode(r.get_attribute("Id")); + auto target = try_decode(r.get_attribute("Target")); + + if (!id.empty() && !target.empty()) + rels[id] = target; + } + } + } + + depth = next_depth; + } + + return rels; +} + +namespace xlcpp { + +sheet& workbook_pimpl::add_sheet(string_view name, bool visible) { + return *sheets.emplace(sheets.end(), *this, name, sheets.size() + 1, visible); +} + +sheet& workbook::add_sheet(string_view name, bool visible) { + return impl->add_sheet(name, visible); +} + +class _formatted_error : public exception { +public: + template + _formatted_error(T&& s, Args&&... args) { + msg = fmt::format(s, forward(args)...); + } + + const char* what() const noexcept { + return msg.c_str(); + } + +private: + string msg; +}; + +#define formatted_error(s, ...) _formatted_error(FMT_COMPILE(s), ##__VA_ARGS__) + +static string make_reference(unsigned int row, unsigned int col) { + char colstr[5]; + + col--; + + if (col < 26) { + colstr[0] = (char)(col + 'A'); + colstr[1] = 0; + } else if (col < 702) { + colstr[0] = (char)((col / 26) - 1 + 'A'); + colstr[1] = (char)((col % 26) + 'A'); + colstr[2] = 0; + } else if (col < 16384) { + colstr[0] = (char)((col / 676) - 1 + 'A'); + colstr[1] = (char)(((col / 26) % 26) - 1 + 'A'); + colstr[2] = (char)((col % 26) + 'A'); + colstr[3] = 0; + } else + Rcpp::stop("Column {} too large.", col); + + return string(colstr) + to_string(row); +} + +// hopefully from_chars will be constexpr some day - see P2291R0 +template +requires is_integral_v && is_unsigned_v +static constexpr from_chars_result from_chars_constexpr(const char* first, const char* last, T& t) { + from_chars_result res; + + res.ptr = first; + res.ec = {}; + + t = 0; + + if (first == last || *first < '0' || *first > '9') + return res; + + while (first != last && *first >= '0' && *first <= '9') { + t *= 10; + t += (T)(*first - '0'); + first++; + res.ptr++; + } + + return res; +} + +static constexpr bool resolve_reference(string_view sv, unsigned int& row, unsigned int& col) noexcept { + from_chars_result fcr; + + if (sv.length() >= 2 && sv[0] >= 'A' && sv[0] <= 'Z' && sv[1] >= '0' && sv[1] <= '9') { + col = sv[0] - 'A'; + fcr = from_chars_constexpr(sv.data() + 1, sv.data() + sv.length(), row); + } else if (sv.length() >= 3 && sv[0] >= 'A' && sv[0] <= 'Z' && sv[1] >= 'A' && sv[1] <= 'Z' && sv[2] >= '0' && sv[2] <= '9') { + col = ((sv[0] - 'A' + 1) * 26) + sv[1] - 'A'; + fcr = from_chars_constexpr(sv.data() + 2, sv.data() + sv.length(), row); + } else if (sv.length() >= 4 && sv[0] >= 'A' && sv[0] <= 'Z' && sv[1] >= 'A' && sv[1] <= 'Z' && sv[2] >= 'A' && sv[2] <= 'Z' && sv[3] >= '0' && sv[3] <= '9') { + col = ((sv[0] - 'A' + 1) * 676) + ((sv[1] - 'A' + 1) * 26) + sv[2] - 'A'; + fcr = from_chars_constexpr(sv.data() + 3, sv.data() + sv.length(), row); + } else + return false; + + if (fcr.ptr != sv.data() + sv.length()) + return false; + + row--; + + return true; +} + +static constexpr bool test_resolve_reference(string_view sv, bool exp_valid, unsigned int exp_row, + unsigned int exp_col) noexcept { + bool valid; + unsigned int row, col; + + valid = resolve_reference(sv, row, col); + + if (!valid) + return !exp_valid; + else if (!exp_valid) + return false; + + return row == exp_row && col == exp_col; +} + +static_assert(test_resolve_reference("", false, 0, 0)); +static_assert(test_resolve_reference("A", false, 0, 0)); +static_assert(test_resolve_reference("1", false, 0, 0)); +static_assert(test_resolve_reference("A1", true, 0, 0)); +static_assert(test_resolve_reference("D3", true, 2, 3)); +static_assert(test_resolve_reference("Z255", true, 254, 25)); +static_assert(test_resolve_reference("AA", false, 0, 0)); +static_assert(test_resolve_reference("AA1", true, 0, 26)); +static_assert(test_resolve_reference("MH229", true, 228, 345)); +static_assert(test_resolve_reference("ZZ16383", true, 16382, 701)); +static_assert(test_resolve_reference("AAA", false, 0, 0)); +static_assert(test_resolve_reference("AAA1", true, 0, 702)); +static_assert(test_resolve_reference("AMJ1048576", true, 1048575, 1023)); + +static constexpr unsigned int date_to_number(const chrono::year_month_day& ymd, bool date1904) noexcept { + int m2 = ((int)(unsigned int)ymd.month() - 14) / 12; + long long n; + + n = (1461 * ((int)ymd.year() + 4800 + m2)) / 4; + n += (367 * ((int)(unsigned int)ymd.month() - 2 - (12 * m2))) / 12; + n -= (3 * (((int)ymd.year() + 4900 + m2)/100)) / 4; + n += (unsigned int)ymd.day(); + n -= 2447094; + + if (date1904) + n -= 1462; + else if (n < 61) // Excel's 29/2/1900 bug + n--; + + return (unsigned int)n; +} + +static_assert(date_to_number(chrono::year_month_day{1900y, chrono::January, 1d}, false) == 1); +static_assert(date_to_number(chrono::year_month_day{1900y, chrono::February, 28d}, false) == 59); +static_assert(date_to_number(chrono::year_month_day{1900y, chrono::March, 1d}, false) == 61); +static_assert(date_to_number(chrono::year_month_day{1998y, chrono::July, 5d}, false) == 35981); +static_assert(date_to_number(chrono::year_month_day{1998y, chrono::July, 5d}, true) == 34519); + +static_assert(number_to_date(1, false) == chrono::year_month_day{1900y, chrono::January, 1d}); +static_assert(number_to_date(59, false) == chrono::year_month_day{1900y, chrono::February, 28d}); +static_assert(number_to_date(61, false) == chrono::year_month_day{1900y, chrono::March, 1d}); +static_assert(number_to_date(35981, false) == chrono::year_month_day{1998y, chrono::July, 5d}); +static_assert(number_to_date(34519, true) == chrono::year_month_day{1998y, chrono::July, 5d}); + +static constexpr double datetime_to_number(const datetime& dt, bool date1904) noexcept { + return (double)date_to_number(dt.d, date1904) + ((double)dt.t.count() / 86400.0); +} + +template +inline constexpr bool always_false_v = false; + +string sheet_pimpl::xml() const { + xml_writer writer; + + writer.start_document(); + + writer.start_element("worksheet", {{"", NS_SPREADSHEET}}); + + writer.start_element("sheetData"); + + for (const auto& r : rows) { + writer.start_element("row"); + + writer.attribute("r", to_string(r.impl->num)); + writer.attribute("customFormat", "false"); + writer.attribute("ht", "12.8"); + writer.attribute("hidden", "false"); + writer.attribute("customHeight", "false"); + writer.attribute("outlineLevel", "0"); + writer.attribute("collapsed", "false"); + + for (const auto& c : r.impl->cells) { + writer.start_element("c"); + + writer.attribute("r", make_reference(r.impl->num, c.impl->num)); + writer.attribute("s", to_string(c.impl->sty->num)); + + visit([&](auto&& arg) { + using T = decay_t; + + if constexpr (is_same_v) { + writer.attribute("t", "n"); // number + + writer.start_element("v"); + writer.text(to_string(arg)); + writer.end_element(); + } else if constexpr (is_same_v) { + writer.attribute("t", "s"); // shared string + + writer.start_element("v"); + writer.text(to_string(arg.num)); + writer.end_element(); + } else if constexpr (is_same_v) { + writer.attribute("t", "n"); // number + + writer.start_element("v"); + writer.text(to_string(arg)); + writer.end_element(); + } else if constexpr (is_same_v) { + writer.attribute("t", "n"); // number + + writer.start_element("v"); + writer.text(to_string(date_to_number(arg, parent.date1904))); + writer.end_element(); + } else if constexpr (is_same_v) { + auto s = (double)arg.count() / 86400.0; + + writer.attribute("t", "n"); // number + + writer.start_element("v"); + writer.text(to_string(s)); + writer.end_element(); + } else if constexpr (is_same_v) { + writer.attribute("t", "n"); // number + + writer.start_element("v"); + writer.text(to_string(datetime_to_number(arg, parent.date1904))); + writer.end_element(); + } else if constexpr (is_same_v) { + writer.attribute("t", "b"); // bool + + writer.start_element("v"); + writer.text(to_string(arg)); + writer.end_element(); + } else if constexpr (is_same_v) { + // nop + } else if constexpr (is_same_v) { + writer.attribute("t", "str"); + + writer.start_element("v"); + writer.text(arg); // FIXME - Unicode should be encoded + writer.end_element(); + } else + static_assert(always_false_v); + }, c.impl->val); + + writer.end_element(); + } + + writer.end_element(); + } + + writer.end_element(); + + writer.end_element(); + + return writer.dump(); +} + +void sheet_pimpl::write(struct archive* a) const { + struct archive_entry* entry; + string data = xml(); + + entry = archive_entry_new(); + archive_entry_set_pathname(entry, ("xl/worksheets/sheet" + to_string(num) + ".xml").c_str()); + archive_entry_set_size(entry, data.length()); + archive_entry_set_filetype(entry, AE_IFREG); + archive_entry_set_perm(entry, 0644); + archive_write_header(a, entry); + archive_write_data(a, data.data(), data.length()); + // FIXME - set date? + archive_entry_free(entry); +} + +void workbook_pimpl::write_workbook_xml(struct archive* a) const { + struct archive_entry* entry; + string data; + + { + xml_writer writer; + + writer.start_document(); + + writer.start_element("workbook", {{"", NS_SPREADSHEET}, {"r", NS_RELATIONSHIPS}}); + + writer.start_element("workbookPr"); + writer.attribute("date1904", date1904 ? "true" : "false"); + writer.end_element(); + + writer.start_element("sheets"); + + for (const auto& sh : sheets) { + writer.start_element("sheet"); + writer.attribute("name", sh.impl->name); + writer.attribute("sheetId", to_string(sh.impl->num)); + writer.attribute("state", "visible"); + writer.attribute("r:id", "rId" + to_string(sh.impl->num)); + writer.end_element(); + } + + writer.end_element(); + + writer.end_element(); + + data = move(writer.dump()); + } + + entry = archive_entry_new(); + archive_entry_set_pathname(entry, "xl/workbook.xml"); + archive_entry_set_size(entry, data.length()); + archive_entry_set_filetype(entry, AE_IFREG); + archive_entry_set_perm(entry, 0644); + archive_write_header(a, entry); + archive_write_data(a, data.data(), data.length()); + // FIXME - set date? + archive_entry_free(entry); +} + +void workbook_pimpl::write_content_types_xml(struct archive* a) const { + struct archive_entry* entry; + string data; + + { + xml_writer writer; + + writer.start_document(); + + writer.start_element("Types", {{"", NS_CONTENT_TYPES}}); + + writer.start_element("Override"); + writer.attribute("PartName", "/xl/workbook.xml"); + writer.attribute("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"); + writer.end_element(); + + for (const auto& sh : sheets) { + writer.start_element("Override"); + writer.attribute("PartName", "/xl/worksheets/sheet" + to_string(sh.impl->num) + ".xml"); + writer.attribute("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"); + writer.end_element(); + } + + writer.start_element("Override"); + writer.attribute("PartName", "/_rels/.rels"); + writer.attribute("ContentType", "application/vnd.openxmlformats-package.relationships+xml"); + writer.end_element(); + + writer.start_element("Override"); + writer.attribute("PartName", "/xl/_rels/workbook.xml.rels"); + writer.attribute("ContentType", "application/vnd.openxmlformats-package.relationships+xml"); + writer.end_element(); + + if (!shared_strings.empty()) { + writer.start_element("Override"); + writer.attribute("PartName", "/xl/sharedStrings.xml"); + writer.attribute("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"); + writer.end_element(); + } + + if (!styles.empty()) { + writer.start_element("Override"); + writer.attribute("PartName", "/xl/styles.xml"); + writer.attribute("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"); + writer.end_element(); + } + + writer.end_element(); + + data = move(writer.dump()); + } + + entry = archive_entry_new(); + archive_entry_set_pathname(entry, "[Content_Types].xml"); + archive_entry_set_size(entry, data.length()); + archive_entry_set_filetype(entry, AE_IFREG); + archive_entry_set_perm(entry, 0644); + archive_write_header(a, entry); + archive_write_data(a, data.data(), data.length()); + // FIXME - set date? + archive_entry_free(entry); +} + +void workbook_pimpl::write_rels(struct archive* a) const { + struct archive_entry* entry; + string data; + + { + xml_writer writer; + + writer.start_document(); + + writer.start_element("Relationships", {{"", "http://schemas.openxmlformats.org/package/2006/relationships"}}); + + writer.start_element("Relationship"); + writer.attribute("Id", "rId1"); + writer.attribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"); + writer.attribute("Target", "/xl/workbook.xml"); + writer.end_element(); + + writer.end_element(); + + data = move(writer.dump()); + } + + entry = archive_entry_new(); + archive_entry_set_pathname(entry, "_rels/.rels"); + archive_entry_set_size(entry, data.length()); + archive_entry_set_filetype(entry, AE_IFREG); + archive_entry_set_perm(entry, 0644); + archive_write_header(a, entry); + archive_write_data(a, data.data(), data.length()); + // FIXME - set date? + archive_entry_free(entry); +} + +void workbook_pimpl::write_workbook_rels(struct archive* a) const { + struct archive_entry* entry; + string data; + + { + unsigned int num = 1; + xml_writer writer; + + writer.start_document(); + + writer.start_element("Relationships", {{"", "http://schemas.openxmlformats.org/package/2006/relationships"}}); + + for (const auto& sh : sheets) { + writer.start_element("Relationship"); + writer.attribute("Id", "rId" + to_string(num)); + writer.attribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"); + writer.attribute("Target", "worksheets/sheet" + to_string(sh.impl->num) + ".xml"); + writer.end_element(); + num++; + } + + if (!shared_strings.empty()) { + writer.start_element("Relationship"); + writer.attribute("Id", "rId" + to_string(num)); + writer.attribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"); + writer.attribute("Target", "sharedStrings.xml"); + writer.end_element(); + num++; + } + + if (!styles.empty()) { + writer.start_element("Relationship"); + writer.attribute("Id", "rId" + to_string(num)); + writer.attribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"); + writer.attribute("Target", "styles.xml"); + writer.end_element(); + } + + writer.end_element(); + + data = move(writer.dump()); + } + + entry = archive_entry_new(); + archive_entry_set_pathname(entry, "xl/_rels/workbook.xml.rels"); + archive_entry_set_size(entry, data.length()); + archive_entry_set_filetype(entry, AE_IFREG); + archive_entry_set_perm(entry, 0644); + archive_write_header(a, entry); + archive_write_data(a, data.data(), data.length()); + // FIXME - set date? + archive_entry_free(entry); +} + +void workbook_pimpl::write_shared_strings(struct archive* a) const { + struct archive_entry* entry; + string data; + + { + xml_writer writer; + + writer.start_document(); + + writer.start_element("sst", {{"", NS_SPREADSHEET}}); + writer.attribute("count", to_string(shared_strings.size())); + writer.attribute("uniqueCount", to_string(shared_strings.size())); + + vector strings; + + strings.resize(shared_strings.size()); + + for (const auto& ss : shared_strings) { + strings[ss.second.num] = ss.first; + } + + for (const auto& s : strings) { + writer.start_element("si"); + + writer.start_element("t"); + writer.attribute("xml:space", "preserve"); + writer.text(s); + writer.end_element(); + + writer.end_element(); + } + + writer.end_element(); + + data = move(writer.dump()); + } + + entry = archive_entry_new(); + archive_entry_set_pathname(entry, "xl/sharedStrings.xml"); + archive_entry_set_size(entry, data.length()); + archive_entry_set_filetype(entry, AE_IFREG); + archive_entry_set_perm(entry, 0644); + archive_write_header(a, entry); + archive_write_data(a, data.data(), data.length()); + // FIXME - set date? + archive_entry_free(entry); +} + +void workbook_pimpl::write_styles(struct archive* a) const { + struct archive_entry* entry; + string data; + + { + xml_writer writer; + vector sty; + vector number_format_nums; + unordered_map number_formats; + vector number_formats2; + font default_font("Arial", 10, false); + unordered_map fonts; + vector fonts2; + + writer.start_document(); + + writer.start_element("styleSheet"); + writer.attribute("xmlns", NS_SPREADSHEET); + + fonts[default_font] = 0; + fonts2.emplace_back(&default_font); + + for (const auto& s : styles) { + if (number_formats.find(s.number_format) == number_formats.end()) { + number_formats[s.number_format] = (unsigned int)number_formats.size(); + number_formats2.emplace_back(&s.number_format); + } + + if (fonts.find(s.font) == fonts.end()) { + fonts[s.font] = (unsigned int)fonts.size(); + fonts2.emplace_back(&s.font); + } + } + + writer.start_element("numFmts"); + writer.attribute("count", to_string(number_formats.size())); + + for (unsigned int i = 0; i < number_formats.size(); i++) { + writer.start_element("numFmt"); + writer.attribute("numFmtId", to_string(i + NUMFMT_OFFSET)); + writer.attribute("formatCode", *number_formats2[i]); + writer.end_element(); + } + + writer.end_element(); + + writer.start_element("fonts"); + writer.attribute("count", to_string(fonts.size())); + + for (unsigned int i = 0; i < fonts.size(); i++) { + writer.start_element("font"); + + if (fonts2[i]->bold) { + writer.start_element("b"); + writer.attribute("val", "true"); + writer.end_element(); + } + + writer.start_element("sz"); + writer.attribute("val", to_string(fonts2[i]->font_size)); + writer.end_element(); + + writer.start_element("name"); + writer.attribute("val", fonts2[i]->font_name); + writer.end_element(); + + writer.end_element(); + } + + writer.end_element(); + + writer.start_element("fills"); + writer.attribute("count", "2"); + + writer.start_element("fill"); + writer.start_element("patternFill"); + writer.attribute("patternType", "none"); + writer.end_element(); + writer.end_element(); + + writer.start_element("fill"); + writer.start_element("patternFill"); + writer.attribute("patternType", "gray125"); + writer.end_element(); + writer.end_element(); + + writer.end_element(); + + writer.start_element("borders"); + writer.attribute("count", "1"); + + writer.start_element("border"); + writer.start_element("left"); writer.end_element(); + writer.start_element("right"); writer.end_element(); + writer.start_element("top"); writer.end_element(); + writer.start_element("bottom"); writer.end_element(); + writer.start_element("diagonal"); writer.end_element(); + writer.end_element(); + + writer.end_element(); + + sty.resize(styles.size()); + + for (const auto& s : styles) { + sty[s.num] = &s; + } + + { + unsigned int style_id = 0; + + writer.start_element("cellXfs"); + writer.attribute("count", to_string(styles.size())); + + for (const auto& s : sty) { + writer.start_element("xf"); + writer.attribute("numFmtId", to_string(number_formats[s->number_format] + NUMFMT_OFFSET)); + writer.attribute("fontId", to_string(fonts[s->font])); + writer.attribute("fillId", "0"); + writer.attribute("borderId", "0"); + writer.attribute("applyFont", "true"); + writer.attribute("applyNumberFormat", "true"); + writer.end_element(); + + style_id++; + } + + writer.end_element(); + } + + writer.end_element(); + + data = move(writer.dump()); + } + + entry = archive_entry_new(); + archive_entry_set_pathname(entry, "xl/styles.xml"); + archive_entry_set_size(entry, data.length()); + archive_entry_set_filetype(entry, AE_IFREG); + archive_entry_set_perm(entry, 0644); + archive_write_header(a, entry); + archive_write_data(a, data.data(), data.length()); + // FIXME - set date? + archive_entry_free(entry); +} + +void workbook_pimpl::write_archive(struct archive* a) const { + for (const auto& sh : sheets) { + sh.impl->write(a); + } + + write_workbook_xml(a); + write_content_types_xml(a); + write_rels(a); + write_workbook_rels(a); + + if (!shared_strings.empty()) + write_shared_strings(a); + + if (!styles.empty()) + write_styles(a); +} + +void workbook_pimpl::save(const filesystem::path& fn) const { + struct archive* a; + + a = archive_write_new(); + archive_write_set_format_zip(a); + + archive_write_open_filename(a, fn.string().c_str()); + + write_archive(a); + + archive_write_close(a); + archive_write_free(a); +} + +void workbook::save(const filesystem::path& fn) const { + impl->save(fn); +} + +static int archive_dummy_callback(struct archive* a, void* client_data) { + return ARCHIVE_OK; +} + +la_ssize_t workbook_pimpl::write_callback(struct archive* a, const void* buffer, size_t length) const { + buf.append((const char*)buffer, length); + + return length; +} + +string workbook_pimpl::data() const { + buf.clear(); + + archive_write_t a{archive_write_new()}; + + archive_write_set_format_zip(a.get()); + archive_write_set_bytes_in_last_block(a.get(), 1); + + auto ret = archive_write_open(a.get(), (void*)this, archive_dummy_callback, + [](struct archive* a, void* client_data, const void* buffer, size_t length) { + auto wb = (const workbook_pimpl*)client_data; + + return wb->write_callback(a, buffer, length); + }, + archive_dummy_callback); + if (ret != ARCHIVE_OK) + Rcpp::stop("archive_write_open returned {}.", ret); + + write_archive(a.get()); + + archive_write_close(a.get()); + + return buf; +} + +string workbook::data() const { + return impl->data(); +} + +row& sheet_pimpl::add_row() { + return *rows.emplace(rows.end(), *this, rows.size() + 1); +} + +row& sheet::add_row() { + return impl->add_row(); +} + +shared_string workbook_pimpl::get_shared_string(string_view s) { + shared_string ss; + + if (shared_strings.contains(s)) + return shared_strings.find(s)->second; + + ss.num = (unsigned int)shared_strings.size(); + + shared_strings.emplace(s, ss); + + return ss; +} + +template +cell_pimpl::cell_pimpl(row_pimpl& r, unsigned int num, const T& t) : parent(r), num(num), val(t) { + if constexpr (is_same_v) + sty = parent.parent.parent.find_style(style("dd/mm/yy", "Arial", 10)); // FIXME - localization + else if constexpr (is_same_v) + sty = parent.parent.parent.find_style(style("HH:MM:SS", "Arial", 10)); // FIXME - localization + else if constexpr (is_same_v) + sty = parent.parent.parent.find_style(style("dd/mm/yy HH:MM:SS", "Arial", 10)); // FIXME - localization + else + sty = parent.parent.parent.find_style(style("General", "Arial", 10)); +} + +cell_pimpl::cell_pimpl(row_pimpl& r, unsigned int num, string_view t) : cell_pimpl(r, num, r.parent.parent.get_shared_string(t)) { +} + +cell::cell(row_pimpl& r, unsigned int num, int64_t val) { + impl = new cell_pimpl(r, num, val); +} + +cell::cell(row_pimpl& r, unsigned int num, string_view val) { + impl = new cell_pimpl(r, num, val); +} + +cell::cell(row_pimpl& r, unsigned int num, double val) { + impl = new cell_pimpl(r, num, val); +} + +cell::cell(row_pimpl& r, unsigned int num, const chrono::year_month_day& val) { + impl = new cell_pimpl(r, num, val); +} + +cell::cell(row_pimpl& r, unsigned int num, const chrono::seconds& val) { + impl = new cell_pimpl(r, num, val); +} + +cell::cell(row_pimpl& r, unsigned int num, const datetime& val) { + impl = new cell_pimpl(r, num, val); +} + +cell::cell(row_pimpl& r, unsigned int num, const chrono::system_clock::time_point& val) { + impl = new cell_pimpl(r, num, val); +} + +cell::cell(row_pimpl& r, unsigned int num, bool val) { + impl = new cell_pimpl(r, num, val); +} + +cell::cell(row_pimpl& r, unsigned int num, nullptr_t) { + impl = new cell_pimpl(r, num, nullptr); +} + +bool operator==(const font& lhs, const font& rhs) noexcept { + return lhs.font_name == rhs.font_name && + lhs.font_size == rhs.font_size && + ((lhs.bold && rhs.bold) || (!lhs.bold && !rhs.bold)); +} + +bool operator==(const style& lhs, const style& rhs) noexcept { + return lhs.number_format == rhs.number_format && + lhs.font == rhs.font; +} + +void style::set_font(string_view font_name, unsigned int font_size, bool bold) { + this->font = xlcpp::font(font_name, font_size, bold); +} + +void style::set_number_format(string_view fmt) { + number_format = fmt; +} + +void cell_pimpl::set_font(string_view name, unsigned int size, bool bold) { + auto sty2 = *sty; + + sty2.set_font(name, size, bold); + + sty = parent.parent.parent.find_style(sty2); +} + +void cell::set_font(string_view name, unsigned int size, bool bold) { + impl->set_font(name, size, bold); +} + +void cell_pimpl::set_number_format(string_view fmt) { + auto sty2 = *sty; + + sty2.set_number_format(fmt); + + sty = parent.parent.parent.find_style(sty2); +} + +void cell::set_number_format(string_view fmt) { + impl->set_number_format(fmt); +} + +workbook::workbook() { + impl = new workbook_pimpl; + impl->date1904 = false; +} + +static void parse_content_types(string_view ct, unordered_map& files) { + xml_reader r(ct); + unsigned int depth = 0; + unordered_map defs, over; + + while (r.read()) { + unsigned int next_depth; + + if (r.node_type() == xml_node::element && !r.is_empty()) + next_depth = depth + 1; + else if (r.node_type() == xml_node::end_element) + next_depth = depth - 1; + else + next_depth = depth; + + if (r.node_type() == xml_node::element) { + if (depth == 0) { + if (r.local_name() != "Types" || !r.namespace_uri_raw().cmp(NS_CONTENT_TYPES)) { + Rcpp::stop("Root tag was {{{}}}{}, expected {{{}}}Types.", + r.namespace_uri_raw().decode(), r.local_name(), NS_CONTENT_TYPES); + } + } else if (depth == 1) { + if (r.local_name() == "Default" && r.namespace_uri_raw().cmp(NS_CONTENT_TYPES)) { + auto ext = try_decode(r.get_attribute("Extension")); + auto ct = try_decode(r.get_attribute("ContentType")); + + defs[ext] = ct; + } else if (r.local_name() == "Override" && r.namespace_uri_raw().cmp(NS_CONTENT_TYPES)) { + auto part = try_decode(r.get_attribute("PartName")); + auto ct = try_decode(r.get_attribute("ContentType")); + + over[part] = ct; + } + } + } + + depth = next_depth; + } + + for (auto& f : files) { + for (const auto& o : over) { + if (o.first == "/" + f.first) { + f.second.content_type = o.second; + break; + } + } + + if (!f.second.content_type.empty()) + continue; + + auto st = f.first.rfind("."); + string ext = st == string::npos ? "" : f.first.substr(st + 1); + + for (const auto& d : defs) { + if (ext == d.first) { + f.second.content_type = d.second; + break; + } + } + } +} + +static const pair& find_workbook(const unordered_map& files) { + for (const auto& f : files) { + if (f.second.content_type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" || + f.second.content_type == "application/vnd.ms-excel.sheet.macroEnabled.main+xml" || + f.second.content_type == "application/vnd.ms-excel.sheet.binary.macroEnabled.main") { + return f; + } + } + + Rcpp::stop("Could not find workbook file."); +} + +string workbook_pimpl::find_number_format(unsigned int num) { + if (num >= cell_styles.size()) + return ""; + + if (!cell_styles[num].has_value()) + return ""; + + unsigned int numfmtid = cell_styles[num].value(); + + for (const auto& nf : number_formats) { + if (nf.first == numfmtid) + return nf.second; + } + + for (const auto& bs : builtin_styles) { + if ((unsigned int)bs.first == numfmtid) + return bs.second; + } + + return ""; +} + +static constexpr bool __inline is_hex(char c) noexcept { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); +} + +static constexpr uint8_t __inline hex_digit(char c) noexcept { + if (c >= '0' && c <= '9') + return (uint8_t)(c - '0'); + else if (c >= 'A' && c <= 'F') + return (uint8_t)(c - 'A' + 0xa); + else if (c >= 'a' && c <= 'f') + return (uint8_t)(c - 'a' + 0xa); + + return 0; +} + +static string decode_escape_sequences(string_view sv) { + bool has_underscore = false; + + if (sv.length() < 7) + return string(sv); + + for (auto c : sv) { + if (c == '_') { + has_underscore = true; + break; + } + } + + if (!has_underscore) + return string(sv); + + string s; + + s.reserve(sv.length()); + + for (unsigned int i = 0; i < sv.length(); i++) { + if (i + 6 < sv.length() && sv[i] == '_' && sv[i+1] == 'x' && is_hex(sv[i+2]) && is_hex(sv[i+3]) && is_hex(sv[i+4]) && is_hex(sv[i+5]) && sv[i+6] == '_') { + auto val = (uint16_t)((hex_digit(sv[i+2]) << 12) | (hex_digit(sv[i+3]) << 8) | (hex_digit(sv[i+4]) << 4) | hex_digit(sv[i+5])); + + if (val < 0x80) + s += (char)val; + else if (val < 0x800) { + char buf[3]; + + buf[0] = (char)(0xc0 | (val >> 6)); + buf[1] = (char)(0x80 | (val & 0x3f)); + buf[2] = 0; + + s += buf; + } else { + char buf[4]; + + buf[0] = (char)(0xe0 | (val >> 12)); + buf[1] = (char)(0x80 | ((val & 0xfc0) >> 6)); + buf[2] = (char)(0x80 | (val & 0x3f)); + buf[3] = 0; + + s += buf; + } + + i += 6; + } else + s += sv[i]; + } + + return s; +} + +static constexpr bool is_valid_date(uint16_t y, uint8_t m, uint8_t d) { + if (y == 0 || m == 0 || d == 0) + return false; + + if (d > 31 || m > 12) + return false; + + if (d == 31 && (m == 4 || m == 6 || m == 9 || m == 11)) + return false; + + if (d == 30 && m == 2) + return false; + + if (d == 29 && m == 2) { + if (y % 4) + return false; + + if (!(y % 100) && y % 400) + return false; + } + + return true; +} + +static constexpr bool __inline is_digit(char c) noexcept { + return c >= '0' && c <= '9'; +} + +static variant parse_iso8601(string_view t) { + if (t.length() >= 10 && is_digit(t[0]) && is_digit(t[1]) && is_digit(t[2]) && is_digit(t[3]) && + t[4] == '-' && is_digit(t[5]) && is_digit(t[6]) && t[7] == '-' && is_digit(t[8]) && + is_digit(t[9])) { + uint16_t y; + uint8_t mon, d; + + from_chars_constexpr(t.data(), t.data() + 4, y); + from_chars_constexpr(t.data() + 5, t.data() + 7, mon); + from_chars_constexpr(t.data() + 8, t.data() + 10, d); + + if (!is_valid_date(y, mon, d)) + Rcpp::stop("Invalid ISO 8601 date \"{}\".", t); + + if (t.length() >= 19 && t[10] == 'T' && is_digit(t[11]) && is_digit(t[12]) && t[13] == ':' && + is_digit(t[14]) && is_digit(t[15]) && t[16] == ':' && is_digit(t[17]) && is_digit(t[18])) { + uint8_t h, mins, s; + + from_chars_constexpr(t.data() + 11, t.data() + 13, h); + from_chars_constexpr(t.data() + 14, t.data() + 16, mins); + from_chars_constexpr(t.data() + 17, t.data() + 19, s); + + if (h >= 24 || mins >= 60 || s >= 60) + Rcpp::stop("Invalid ISO 8601 date \"{}\".", t); + + // FIXME - fractional seconds? + + return datetime(chrono::year{y}, chrono::month{mon}, chrono::day{d}, chrono::hours{h}, chrono::minutes{mins}, chrono::seconds{s}); + } + + return chrono::year_month_day{chrono::year{y}, chrono::month{mon}, chrono::day{d}}; + } else + Rcpp::stop("Failed to parse ISO 8601 date \"{}\".", t); +} + +void workbook_pimpl::load_sheet(string_view name, string_view data, bool visible) { + auto& s = *sheets.emplace(sheets.end(), *this, name, sheets.size() + 1, visible); + + xml_reader r(data); + unsigned int depth = 0; + bool in_sheet_data = false; + unsigned int last_index = 0, last_col = 0; + row* row = nullptr; + string s_val, t_val, v_val, is_val; + bool in_v = false, in_is = false; + + while (r.read()) { + unsigned int next_depth; + + if (r.node_type() == xml_node::element && !r.is_empty()) + next_depth = depth + 1; + else if (r.node_type() == xml_node::end_element) + next_depth = depth - 1; + else + next_depth = depth; + + if (r.node_type() == xml_node::element) { + if (depth == 0) { + if (r.local_name() != "worksheet" || (!r.namespace_uri_raw().cmp(NS_SPREADSHEET) && !r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { + Rcpp::stop("Root tag was {{{}}}{}, expected {{{}}}worksheet.", + r.namespace_uri_raw().decode(), r.local_name(), NS_SPREADSHEET); + } + } else if (depth == 1 && r.local_name() == "sheetData" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT)) && !r.is_empty()) + in_sheet_data = true; + else if (in_sheet_data) { + if (r.local_name() == "row" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { + unsigned int row_index = 0; + auto rsv = r.get_attribute("r"); + + if (rsv) { + auto value = rsv.value().decode(); + auto [ptr, ec] = from_chars(value.data(), value.data() + value.length(), row_index); + + if (ptr != value.data() + value.length()) + Rcpp::stop("Invalid r attribute \"{}\" for row tag.", value); + } + + if (row_index == 0) + Rcpp::stop("No row index given."); + + if (row_index <= last_index) + Rcpp::stop("Rows out of order."); + + while (last_index + 1 < row_index) { + s.impl->rows.emplace(s.impl->rows.end(), *s.impl, s.impl->rows.size() + 1); + last_index++; + } + + s.impl->rows.emplace(s.impl->rows.end(), *s.impl, s.impl->rows.size() + 1); + + row = &s.impl->rows.back(); + + last_index = row_index; + last_col = 0; + } else if (row && r.local_name() == "c" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { + unsigned int row_num, col_num; + auto r_val = try_decode(r.get_attribute("r")); + + v_val = ""; + is_val = ""; + + t_val = try_decode(r.get_attribute("t")); + s_val = try_decode(r.get_attribute("s")); + + if (r_val.empty()) + Rcpp::stop("Cell had no r value."); + + if (!resolve_reference(r_val, row_num, col_num)) + Rcpp::stop("Malformed reference \"{}\".", r_val); + + if (row_num + 1 != last_index) + Rcpp::stop("Cell was in wrong row."); + + if (col_num < last_col) + Rcpp::stop("Cells out of order."); + + while (last_col < col_num) { + row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + last_col++; + } + + last_col = col_num + 1; + + if (r.is_empty()) + row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + } else if (row && r.local_name() == "v" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT)) && !r.is_empty()) + in_v = true; + else if (row && r.local_name() == "is" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT)) && !r.is_empty()) + in_is = true; + } + } else if (r.node_type() == xml_node::end_element) { + if (depth == 1 && r.local_name() == "sheetData" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) + in_sheet_data = false; + else if (depth == 2 && r.local_name() == "row" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) + row = nullptr; + else if (row && r.local_name() == "c" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { + cell* c; + string number_format; + + if (!s_val.empty()) + number_format = find_number_format(stoi(s_val)); + + if (t_val == "n" || t_val.empty()) { // number + bool dt = is_date(number_format); + bool tm = is_time(number_format); + + // FIXME - we can optimize is_date and is_time if one of the preset number formats + + if (dt && tm) { + auto d = stod(v_val); + auto n = (unsigned int)((d - (int)d) * 86400.0); + datetime dt(1970y, chrono::January, 1d, chrono::seconds{n}); + + dt.d = number_to_date((int)d, date1904); + + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, dt); + } else if (dt) { + int num; + + auto [ptr, ec] = from_chars(v_val.data(), v_val.data() + v_val.length(), num); + + if (ec == errc() && ptr == v_val.data() + v_val.length()) { + auto ymd = number_to_date(num, date1904); + + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, ymd); + } else + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + } else if (tm) { + auto n = (unsigned int)(stod(v_val) * 86400.0); + + chrono::seconds t{n % 86400}; + + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, t); + } else { + bool is_int = true; + + for (const auto c : v_val) { + if (c != '-' && (c < '0' || c > '9')) { + is_int = false; + break; + } + } + + if (is_int) { + int64_t val; + + auto [ptr, ec] = from_chars(v_val.data(), v_val.data() + v_val.length(), val); + + if (ptr != v_val.data() + v_val.length()) + Rcpp::stop("Could not convert {} to int64_t.", v_val); + + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, val); + } else + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, stod(v_val)); + } + } else if (t_val == "b") // boolean + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, stoi(v_val) != 0); + else if (t_val == "s") { // shared string + shared_string ss; + + auto [ptr, ec] = from_chars(v_val.data(), v_val.data() + v_val.length(), ss.num); + + if (ptr != v_val.data() + v_val.length()) + Rcpp::stop("Invalid v attribute \"{}\" on shared-string cell.", v_val); + + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + + // so we don't have to expose shared_string publicly + delete c->impl; + c->impl = new cell_pimpl(*row->impl, (unsigned int)row->impl->cells.size(), ss); + } else if (t_val == "e") // error + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + else if (t_val == "str") { // string + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + + if (!v_val.empty()) { + // so we don't have to expose shared_string publicly + c->impl->val = decode_escape_sequences(v_val); + } + } else if (t_val == "inlineStr") { // inline string + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + + if (!is_val.empty()) { + // so we don't have to expose shared_string publicly + c->impl->val = decode_escape_sequences(is_val); + } + } else if (t_val == "d") { // datetime + auto dt = parse_iso8601(v_val); + + visit([&](auto&& arg) { + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, arg); + }, dt); + } else + Rcpp::stop("Unhandled cell type value \"{}\".", t_val); + + if (!s_val.empty()) + c->impl->number_format = number_format; + } else if (in_v && r.local_name() == "v" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) + in_v = false; + else if (in_is && r.local_name() == "is" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) + in_is = false; + } else if (r.node_type() == xml_node::text) { + if (in_v) + v_val += r.value(); + else if (in_is) + is_val += r.value(); + } + + depth = next_depth; + } +} + +void workbook_pimpl::parse_workbook(string_view fn, string_view data, const unordered_map& files) { + xml_reader r(data); + unsigned int depth = 0; + + struct sheet_info { + sheet_info(string_view rid, string_view name, bool visible) : + rid(rid), name(name), visible(visible) { } + + string rid; + string name; + bool visible; + }; + + vector sheets_rels; + + while (r.read()) { + unsigned int next_depth; + + if (r.node_type() == xml_node::element && !r.is_empty()) + next_depth = depth + 1; + else if (r.node_type() == xml_node::end_element) + next_depth = depth - 1; + else + next_depth = depth; + + if (r.node_type() == xml_node::element) { + if (depth == 0) { + if (r.local_name() != "workbook" || (!r.namespace_uri_raw().cmp(NS_SPREADSHEET) && !r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { + Rcpp::stop("Root tag was {{{}}}{}, expected {{{}}}workbook.", + r.namespace_uri_raw().decode(), r.local_name(), NS_SPREADSHEET); + } + } else if (depth == 1) { + if (r.local_name() == "workbookPr" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { + auto date1904sv = r.get_attribute("date1904"); + + if (date1904sv) { + auto value = date1904sv.value().decode(); + date1904 = value == "true" || value == "1"; + } + } + } else if (depth == 2) { + if (r.local_name() == "sheet" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { + bool visible = true; + + auto sheet_name = try_decode(r.get_attribute("name")); + string rid; + + if (r.get_attribute("id", NS_RELATIONSHIPS).has_value()) + rid = r.get_attribute("id", NS_RELATIONSHIPS).value().decode(); + else if (r.get_attribute("id", NS_RELATIONSHIPS_STRICT).has_value()) + rid = r.get_attribute("id", NS_RELATIONSHIPS_STRICT).value().decode(); + + if (!rid.empty()) { + auto statesv = r.get_attribute("state"); + if (statesv) + visible = statesv.value().decode() != "hidden"; + + if (!sheet_name.empty()) + sheets_rels.emplace_back(rid, sheet_name, visible); + } + } + } + } + + depth = next_depth; + } + + // FIXME - preserve sheet order + + auto rels = read_relationships(fn, files); + + for (const auto& sr : sheets_rels) { + for (const auto& r : rels) { + if (r.first == sr.rid) { + auto name = filesystem::path(fn); + + // FIXME - can we resolve relative paths properly? + + name.remove_filename(); + name /= r.second; + + auto ns = name.string(); + + for (auto& c : ns) { + if (c == '\\') + c = '/'; + } + + if (files.count(ns) == 0) + Rcpp::stop("File {} not found.", ns); + + load_sheet(sr.name, files.at(ns).data, sr.visible); + break; + } + } + } +} + +void workbook_pimpl::load_shared_strings2(string_view sv) { + xml_reader r(sv); + unsigned int depth = 0; + bool in_si = false; + string si_val; + + while (r.read()) { + unsigned int next_depth; + + if (r.node_type() == xml_node::element && !r.is_empty()) + next_depth = depth + 1; + else if (r.node_type() == xml_node::end_element) + next_depth = depth - 1; + else + next_depth = depth; + + if (r.node_type() == xml_node::element) { + if (depth == 0) { + if (r.local_name() != "sst" || (!r.namespace_uri_raw().cmp(NS_SPREADSHEET) && !r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { + Rcpp::stop("Root tag was {{{}}}{}, expected {{{}}}sst.", + r.namespace_uri_raw().decode(), r.local_name(), NS_SPREADSHEET); + } + } else if (depth == 1) { + if (r.local_name() == "si" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { + in_si = true; + si_val = ""; + } + } + } else if (r.node_type() == xml_node::text) { + if (in_si) + si_val += decode_escape_sequences(r.value()); + } else if (r.node_type() == xml_node::end_element) { + if (r.local_name() == "si" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { + shared_strings2.emplace_back(si_val); + in_si = false; + } + } + + depth = next_depth; + } +} + +void workbook_pimpl::load_shared_strings(const unordered_map& files) { + for (const auto& f : files) { + if (f.second.content_type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml") { + load_shared_strings2(f.second.data); + return; + } else if (f.second.content_type == "application/vnd.ms-excel.sharedStrings") { + load_shared_strings_binary(span((uint8_t*)f.second.data.data(), f.second.data.size())); + return; + } + } +} + +void workbook_pimpl::load_styles2(string_view sv) { + xml_reader r(sv); + unsigned int depth = 0; + bool in_numfmts = false, in_cellxfs = false; + + while (r.read()) { + unsigned int next_depth; + + if (r.node_type() == xml_node::element && !r.is_empty()) + next_depth = depth + 1; + else if (r.node_type() == xml_node::end_element) + next_depth = depth - 1; + else + next_depth = depth; + + if (r.node_type() == xml_node::element) { + if (depth == 0) { + if (r.local_name() != "styleSheet" || (!r.namespace_uri_raw().cmp(NS_SPREADSHEET) && !r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { + Rcpp::stop("Root tag was {{{}}}{}, expected {{{}}}styleSheet.", + r.namespace_uri_raw().decode(), r.local_name(), NS_SPREADSHEET); + } + } else if (depth == 1) { + if (r.local_name() == "numFmts" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT)) && !r.is_empty()) + in_numfmts = true; + else if (r.local_name() == "cellXfs" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT)) && !r.is_empty()) + in_cellxfs = true; + } else if (depth == 2) { + if (in_numfmts && r.local_name() == "numFmt" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { + unsigned int id = 0; + string format_code; + + auto numfmtsv = r.get_attribute("numFmtId"); + if (numfmtsv) { + auto value = numfmtsv.value().decode(); + auto fcr = from_chars(value.data(), value.data() + value.length(), id); + + if (fcr.ec != errc() || fcr.ptr != value.data() + value.length()) + Rcpp::stop("Failed to parse numFmtId value {}.", value); + + if (id != 0) + number_formats[id] = try_decode(r.get_attribute("formatCode")); + } + } else if (in_cellxfs && r.local_name() == "xf" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { + optional numfmtid; + bool apply_number_format = true; + + auto numfmtsv = r.get_attribute("numFmtId"); + if (numfmtsv) { + unsigned int num; + + auto value = numfmtsv.value().decode(); + auto fcr = from_chars(value.data(), value.data() + value.length(), num); + + if (fcr.ec != errc() || fcr.ptr != value.data() + value.length()) + Rcpp::stop("Failed to parse numFmtId value {}.", value); + + numfmtid = num; + } + + auto applysv = r.get_attribute("applyNumberFormat"); + if (applysv) { + auto value = applysv.value().decode(); + apply_number_format = value == "true" || value == "1"; + } + + if (!apply_number_format) + numfmtid = nullopt; + + cell_styles.push_back(numfmtid); + } + } + } else if (r.node_type() == xml_node::end_element) { + if (in_numfmts && r.local_name() == "numFmts" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) + in_numfmts = false; + else if (in_cellxfs && r.local_name() == "cellXfs" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) + in_cellxfs = false; + } + + depth = next_depth; + } +} + +void workbook_pimpl::load_styles(const unordered_map& files) { + for (const auto& f : files) { + if (f.second.content_type == "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml") { + load_styles2(f.second.data); + return; + } else if (f.second.content_type == "application/vnd.ms-excel.styles") { + load_styles_binary(span((uint8_t*)f.second.data.data(), f.second.data.size())); + return; + } + } +} + +#ifdef _WIN32 +__inline string utf16_to_utf8(const u16string_view& s) { + string ret; + + if (s.empty()) + return ""; + + auto len = WideCharToMultiByte(CP_UTF8, 0, (const wchar_t*)s.data(), (int)s.length(), nullptr, 0, + nullptr, nullptr); + + if (len == 0) + Rcpp::stop("WideCharToMultiByte 1 failed."); + + ret.resize(len); + + len = WideCharToMultiByte(CP_UTF8, 0, (const wchar_t*)s.data(), (int)s.length(), ret.data(), len, + nullptr, nullptr); + + if (len == 0) + Rcpp::stop("WideCharToMultiByte 2 failed."); + + return ret; +} +#endif + +void workbook_pimpl::load_archive(struct archive* a) { + struct archive_entry* entry; + unordered_map files; + + while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { + if (archive_entry_filetype(entry) == AE_IFREG && archive_entry_pathname(entry)) { + filesystem::path name = archive_entry_pathname(entry); + auto ext = name.extension().string(); + + for (auto& c : ext) { + if (c >= 'A' && c <= 'Z') + c = c - 'A' + 'a'; + } + + if (ext != ".xml" && ext != ".rels" && ext != ".bin") + continue; + + string buf; + string tmp(BLOCK_SIZE, 0); + + do { + auto read = archive_read_data(a, tmp.data(), BLOCK_SIZE); + + if (read == 0) + break; + + if (read < 0) + Rcpp::stop("archive_read_data returned {} for {} ({})", read, name.string(), archive_error_string(a)); + + buf += tmp.substr(0, read); + } while (true); + + files[name.string()].data = buf; + } + } + + if (files.count("[Content_Types].xml") == 0) + Rcpp::stop("[Content_Types].xml not found."); + + parse_content_types(files.at("[Content_Types].xml").data, files); + + load_shared_strings(files); + + load_styles(files); + + auto& wb = find_workbook(files); + + if (wb.second.content_type == "application/vnd.ms-excel.sheet.binary.macroEnabled.main") + parse_workbook_binary(wb.first, span((uint8_t*)wb.second.data.data(), wb.second.data.size()), files); + else + parse_workbook(wb.first, wb.second.data, files); +} + +workbook_pimpl::workbook_pimpl(const filesystem::path& fn, string_view password, string_view outfile) { +#ifdef _WIN32 + unique_handle hup{CreateFileW((LPCWSTR)fn.u16string().c_str(), FILE_READ_DATA | DELETE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, nullptr)}; + if (hup.get() == INVALID_HANDLE_VALUE) + throw last_error("CreateFile", GetLastError()); +#else + unique_handle hup{open(fn.string().c_str(), O_RDONLY)}; + + if (hup.get() == -1) + Rcpp::stop("open failed (errno = {})", errno); +#endif + + mmap m(hup.get()); + + auto mem = m.map(); + + load_from_memory(mem, password, outfile); +} + +workbook_pimpl::workbook_pimpl(span sv, string_view password, string_view outfile) { + load_from_memory(sv, password, outfile); +} + +void workbook_pimpl::load_from_memory(span mem, string_view password, string_view outfile) { + vector plaintext; + + if (mem.size() >= sizeof(uint64_t) && *(uint64_t*)mem.data() == CFBF_SIGNATURE) { + cfbf c(mem); + string enc_info, enc_package; + + // FIXME - handle old-style Excel files + + for (unsigned int num = 0; const auto& e : c.entries) { + if (num == 0) { // root + num++; + continue; + } + + if (e.name == "/EncryptionInfo" || e.name == "/EncryptedPackage") { + auto& str = e.name == "/EncryptionInfo" ? enc_info : enc_package; + + str.resize(e.get_size()); + + uint64_t off = 0; + auto buf = span((std::byte*)str.data(), str.size()); + + while (true) { + auto size = e.read(buf, off); + + if (size == 0) + break; + + off += size; + } + } + + num++; + } + + if (enc_info.empty()) + Rcpp::stop("EncryptionInfo not found."); + + auto u16password = utf8_to_utf16(password); + + c.parse_enc_info(span((uint8_t*)enc_info.data(), enc_info.size()), u16password); + plaintext = c.decrypt(span((uint8_t*)enc_package.data(), enc_package.size())); + + mem = plaintext; + } + + archive_read_t a{archive_read_new()}; + + archive_read_support_format_zip(a.get()); + + auto r = archive_read_open_memory(a.get(), mem.data(), mem.size()); + + if (r != ARCHIVE_OK) + Rcpp::stop("{}", archive_error_string(a.get())); + + // archive_read_t b{archive_read_new()}; + // archive_write_set_format_zip(b.get()); + // archive_write_open_filename(b.get(), "/tmp/test.xlsx"); + // // archive_write_data_block(b, mem.data(), mem.size(), 0); + // // archive_write_data(b, mem.data(), mem.size()); + // archive_write_open_memory(b, mem.data(), mem.size()); + // archive_write_close(b.get()); + // archive_write_free(b.get()); + + // FIXME I'm to stupid to write the file with libarchive + + if (outfile.compare("") != 0) { + std::ofstream xlsx((std::string)outfile, ios::out | ios::binary); + xlsx.write((char *) mem.data(), mem.size()); + xlsx.close(); + } + + load_archive(a.get()); +} + +workbook::workbook(const filesystem::path& fn, std::string_view password, std::string_view outfile) { + impl = new workbook_pimpl(fn, password, outfile); +} + +workbook::workbook(span sv, std::string_view password, std::string_view outfile) { + impl = new workbook_pimpl(sv, password, outfile); +} + +workbook::~workbook() { + delete impl; +} + +sheet::sheet(workbook_pimpl& wb, string_view name, unsigned int num, bool visible) { + impl = new sheet_pimpl(wb, name, num, visible); +} + +sheet::~sheet() { + delete impl; +} + +row::row(sheet_pimpl& s, unsigned int num) { + impl = new row_pimpl(s, num); +} + +row::~row() { + delete impl; +} + +cell& row::add_cell(int64_t val) { + return impl->add_cell(val); +} + +cell& row::add_cell(string_view val) { + return impl->add_cell(val); +} + +cell& row::add_cell(double val) { + return impl->add_cell(val); +} + +cell& row::add_cell(const chrono::year_month_day& val) { + return impl->add_cell(val); +} + +cell& row::add_cell(const chrono::seconds& val) { + return impl->add_cell(val); +} + +cell& row::add_cell(const datetime& val) { + return impl->add_cell(val); +} + +cell& row::add_cell(const chrono::system_clock::time_point& val) { + return impl->add_cell(val); +} + +cell& row::add_cell(bool val) { + return impl->add_cell(val); +} + +cell& row::add_cell(nullptr_t) { + return impl->add_cell(nullptr); +} + +const list& workbook::sheets() const { + return impl->sheets; +} + +string sheet::name() const { + return impl->name; +} + +bool sheet::visible() const { + return impl->visible; +} + +const list& sheet::rows() const { + return impl->rows; +} + +const list& row::cells() const { + return impl->cells; +} + +ostream& operator<<(ostream& os, const cell& c) { + visit([&](auto&& arg) { + using T = decay_t; + + if constexpr (is_same_v) + os << arg; + else if constexpr (is_same_v) + os << arg; + else if constexpr (is_same_v) + os << (arg ? "true" : "false"); + else if constexpr (is_same_v) + os << c.impl->parent.parent.parent.shared_strings2[arg.num]; + else if constexpr (is_same_v) + os << fmt::format("{:04}-{:02}-{:02}", (int)arg.year(), (unsigned int)arg.month(), (unsigned int)arg.day()); + else if constexpr (is_same_v) { + const auto& t = chrono::hh_mm_ss{arg}; + + os << fmt::format("{:02}:{:02}:{:02}", t.hours().count(), t.minutes().count(), t.seconds().count()); + } else if constexpr (is_same_v) { + const auto& t = chrono::hh_mm_ss{arg.t}; + + os << fmt::format("{:04}-{:02}-{:02} {:02}:{:02}:{:02}", + (int)arg.d.year(), (unsigned int)arg.d.month(), (unsigned int)arg.d.day(), + t.hours().count(), t.minutes().count(), t.seconds().count()); + } else if constexpr (is_same_v) { + // nop + } else if constexpr (is_same_v) + os << arg; + else + static_assert(always_false_v); + }, c.impl->val); + + return os; +} + +string cell::get_number_format() const { + return impl->number_format; +} + +cell_t cell::value() const { + decltype(value()) v; + + visit([&](auto&& arg) { + if constexpr (is_same_v, shared_string>) + v = impl->parent.parent.parent.shared_strings2[get(impl->val).num]; + else + v = arg; + }, impl->val); + + return v; +} + +#ifdef _WIN32 +void workbook_pimpl::rename(const filesystem::path& fn) const { + vector buf; + auto dest = fn.u16string(); + + buf.resize(offsetof(FILE_RENAME_INFO, FileName) + ((dest.length() + 1) * sizeof(char16_t))); + + auto fri = (FILE_RENAME_INFO*)buf.data(); + + fri->ReplaceIfExists = true; + fri->RootDirectory = nullptr; + fri->FileNameLength = (DWORD)(dest.length() * sizeof(char16_t)); + memcpy(fri->FileName, dest.data(), fri->FileNameLength); + fri->FileName[dest.length()] = 0; + + if (!SetFileInformationByHandle(h.get(), FileRenameInfo, fri, (DWORD)buf.size())) + throw last_error("SetFileInformationByHandle", GetLastError()); +} + +void workbook::rename(const filesystem::path& fn) const { + impl->rename(fn); +} +#endif + +} diff --git a/src/xlcpp/xlcpp.h b/src/xlcpp/xlcpp.h new file mode 100644 index 000000000..fac2fcaed --- /dev/null +++ b/src/xlcpp/xlcpp.h @@ -0,0 +1,155 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 + +#include + +#ifdef XLCPP_EXPORT +#define XLCPP __declspec(dllexport) +#elif !defined(XLCPP_STATIC) +#define XLCPP __declspec(dllimport) +#else +#define XLCPP +#endif + +#else + +#ifdef XLCPP_EXPORT +#define XLCPP __attribute__ ((visibility ("default"))) +#elif !defined(XLCPP_STATIC) +#define XLCPP __attribute__ ((dllimport)) +#else +#define XLCPP +#endif + +#endif + +namespace xlcpp { + +class workbook_pimpl; +class sheet; + +class XLCPP workbook { +public: + workbook(); + workbook(const std::filesystem::path& fn, std::string_view password = "", std::string_view outfile = ""); + workbook(std::span sv, std::string_view password = "", std::string_view outfile = ""); + ~workbook(); + sheet& add_sheet(std::string_view name, bool visible = true); + void save(const std::filesystem::path& fn) const; + std::string data() const; + const std::list& sheets() const; +#ifdef _WIN32 + void rename(const std::filesystem::path& fn) const; +#endif + + workbook_pimpl* impl; +}; + +class sheet_pimpl; +class row; + +class XLCPP sheet { +public: + sheet(workbook_pimpl& wb, std::string_view name, unsigned int num, bool visible = true); + ~sheet(); + row& add_row(); + std::string name() const; + bool visible() const; + const std::list& rows() const; + + sheet_pimpl* impl; +}; + +class XLCPP datetime { +public: + constexpr datetime(std::chrono::year year, std::chrono::month month, std::chrono::day day, std::chrono::hours hour, std::chrono::minutes minute, std::chrono::seconds second) : + d(year, month, day), t(hour + minute + second) { } + constexpr datetime(std::chrono::year year, std::chrono::month month, std::chrono::day day, std::chrono::seconds t) : + d(year, month, day), t(t) { } + + template + constexpr datetime(const std::chrono::time_point& chr) : + d(std::chrono::floor(chr)), + t(std::chrono::floor(chr - std::chrono::floor(chr)).count()) { + } + + std::chrono::year_month_day d; + std::chrono::seconds t; +}; + +class row_pimpl; +class cell_pimpl; + +using cell_t = std::variant; + +class XLCPP cell { +public: + cell(row_pimpl& r, unsigned int num, std::nullptr_t); + cell(row_pimpl& r, unsigned int num, int64_t val); + cell(row_pimpl& r, unsigned int num, std::string_view val); + cell(row_pimpl& r, unsigned int num, double val); + cell(row_pimpl& r, unsigned int num, const std::chrono::year_month_day& val); + cell(row_pimpl& r, unsigned int num, const std::chrono::seconds& val); + cell(row_pimpl& r, unsigned int num, const datetime& val); + cell(row_pimpl& r, unsigned int num, const std::chrono::system_clock::time_point& val); + cell(row_pimpl& r, unsigned int num, bool val); + + template + cell(row_pimpl& r, unsigned int num, T* t) = delete; + + void set_number_format(std::string_view fmt); + void set_font(std::string_view name, unsigned int size, bool bold = false); + std::string get_number_format() const; + cell_t value() const; + + cell_pimpl* impl; +}; + +XLCPP std::ostream& operator<<(std::ostream& os, const cell& c); + +class XLCPP row { +public: + row(sheet_pimpl& s, unsigned int num); + ~row(); + + cell& add_cell(int64_t val); + cell& add_cell(std::string_view val); + cell& add_cell(double val); + cell& add_cell(const std::chrono::year_month_day& val); + cell& add_cell(const std::chrono::seconds& val); + cell& add_cell(const datetime& val); + cell& add_cell(const std::chrono::system_clock::time_point& val); + cell& add_cell(bool val); + cell& add_cell(std::nullptr_t); + + cell& add_cell(const char* val) { + return add_cell(std::string_view(val)); + } + + cell& add_cell(char* val) { + return add_cell(std::string_view(val)); + } + + template + requires std::is_integral_v + cell& add_cell(T val) { + return add_cell(static_cast(val)); + } + + template + cell& add_cell(T* val) = delete; + + const std::list& cells() const; + + row_pimpl* impl; +}; + +}; diff --git a/src/xlcpp/xlsb.cpp b/src/xlcpp/xlsb.cpp new file mode 100644 index 000000000..8bc1e9ea6 --- /dev/null +++ b/src/xlcpp/xlsb.cpp @@ -0,0 +1,565 @@ +#include "openxlsx2.h" + +#include "xlcpp.h" +#include "xlcpp-pimpl.h" +#include "cfbf.h" +#include "utf16.h" +#include "xlsb.h" + +using namespace std; + +namespace xlcpp { + +static void xlsb_walk(span data, const function)>& func) { + while (!data.empty()) { + uint16_t type; + uint32_t length; + + type = data[0]; + data = data.subspan(1); + + if (type & 0x80) { + type = (uint16_t)((type & 0x7f) | ((uint16_t)data[0] << 7)); + data = data.subspan(1); + } + + length = data[0]; + data = data.subspan(1); + + if (length & 0x80) { + length = (length & 0x7f) | ((uint32_t)data[0] << 7); + data = data.subspan(1); + } + + if (length & 0x4000) { + length = (length & 0x3fff) | ((uint32_t)data[0] << 14); + data = data.subspan(1); + } + + if (length & 0x200000) { + length = (length & 0x1fffff) | ((uint32_t)(data[0] & 0x7f) << 21); + data = data.subspan(1); + } + + func((enum xlsb_type)type, data.subspan(0, length)); + + data = data.subspan(length); + } +} + +void workbook_pimpl::load_sheet_binary(string_view name, span data, bool visible) { + auto& s = *sheets.emplace(sheets.end(), *this, name, sheets.size() + 1, visible); + unsigned int last_index = 0, last_col = 0; + row* row = nullptr; + bool in_sheet_data = false; + + xlsb_walk(data, [&](enum xlsb_type type, span d) { + switch (type) { + case xlsb_type::BrtBeginSheetData: + in_sheet_data = true; + break; + + case xlsb_type::BrtEndSheetData: + in_sheet_data = false; + break; + + case xlsb_type::BrtRowHdr: { + if (!in_sheet_data) + break; + + if (d.size() < sizeof(brt_row_hdr)) + Rcpp::stop("Malformed BrtRowHdr record."); + + const auto& h = *(brt_row_hdr*)d.data(); + + if (h.rw < last_index) + Rcpp::stop("Rows out of order."); + + while (last_index < h.rw) { + s.impl->rows.emplace(s.impl->rows.end(), *s.impl, s.impl->rows.size() + 1); + last_index++; + } + + s.impl->rows.emplace(s.impl->rows.end(), *s.impl, s.impl->rows.size() + 1); + + row = &s.impl->rows.back(); + + last_index = h.rw + 1; + last_col = 0; + + break; + } + + case xlsb_type::BrtCellBlank: + case xlsb_type::BrtCellError: + case xlsb_type::BrtFmlaError: { + if (!in_sheet_data) + break; + + if (d.size() < sizeof(xlsb_cell)) + Rcpp::stop("Malformed cell record."); + + const auto& h = *(xlsb_cell*)d.data(); + + if (h.column < last_col) + Rcpp::stop("Cells out of order."); + + while (last_col < h.column) { + row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + last_col++; + } + + last_col = h.column + 1; + + auto number_format = find_number_format(h.iStyleRef); + + row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + break; + } + + case xlsb_type::BrtCellRk: { + if (!in_sheet_data) + break; + + if (d.size() < sizeof(brt_cell_rk)) + Rcpp::stop("Malformed BrtCellRk record."); + + const auto& h = *(brt_cell_rk*)d.data(); + + if (h.cell.column < last_col) + Rcpp::stop("Cells out of order."); + + while (last_col < h.cell.column) { + row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + last_col++; + } + + last_col = h.cell.column + 1; + + auto number_format = find_number_format(h.cell.iStyleRef); + + double d; + + if (h.value.fInt) { + auto num = h.value.num; + auto val = *reinterpret_cast(&num); + + d = val; + } else { + auto num = ((uint64_t)h.value.num) << 34; + d = *reinterpret_cast(&num); + } + + if (h.value.fx100) + d /= 100.0; + + bool dt = is_date(number_format); + bool tm = is_time(number_format); + cell* c; + + // FIXME - we can optimize is_date and is_time if one of the preset number formats + + if (dt && tm) { + auto n = (unsigned int)((d - (int)d) * 86400.0); + datetime dt(1970y, chrono::January, 1d, chrono::seconds{n}); + + dt.d = number_to_date((int)d, date1904); + + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, dt); + } else if (dt) { + auto ymd = number_to_date((unsigned int)d, date1904); + + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, ymd); + } else if (tm) { + auto n = (unsigned int)(d * 86400.0); + chrono::seconds t{n % 86400}; + + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, t); + } else + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, d); + + c->impl->number_format = number_format; + + break; + } + + case xlsb_type::BrtCellBool: + case xlsb_type::BrtFmlaBool: { + if (!in_sheet_data) + break; + + if (d.size() < sizeof(brt_cell_bool)) + Rcpp::stop("Malformed BrtCellBool record."); + + const auto& h = *(brt_cell_bool*)d.data(); + + if (h.cell.column < last_col) + Rcpp::stop("Cells out of order."); + + while (last_col < h.cell.column) { + row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + last_col++; + } + + last_col = h.cell.column + 1; + + auto number_format = find_number_format(h.cell.iStyleRef); + + auto c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, h.fBool != 0); + + c->impl->number_format = number_format; + + break; + } + + case xlsb_type::BrtCellReal: + case xlsb_type::BrtFmlaNum: { + if (!in_sheet_data) + break; + + if (d.size() < sizeof(brt_cell_real)) + Rcpp::stop("Malformed BrtCellReal record."); + + const auto& h = *(brt_cell_real*)d.data(); + + if (h.cell.column < last_col) + Rcpp::stop("Cells out of order."); + + while (last_col < h.cell.column) { + row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + last_col++; + } + + last_col = h.cell.column + 1; + + auto number_format = find_number_format(h.cell.iStyleRef); + + bool dt = is_date(number_format); + bool tm = is_time(number_format); + cell* c; + + if (dt && tm) { + auto n = (unsigned int)((h.xnum - (int)h.xnum) * 86400.0); + datetime dt(1970y, chrono::January, 1d, chrono::seconds{n}); + + dt.d = number_to_date((int)h.xnum, date1904); + + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, dt); + } else if (dt) { + auto ymd = number_to_date((unsigned int)h.xnum, date1904); + + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, ymd); + } else if (tm) { + auto n = (unsigned int)(h.xnum * 86400.0); + chrono::seconds t{n % 86400}; + + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, t); + } else + c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, h.xnum); + + c->impl->number_format = number_format; + + break; + } + + case xlsb_type::BrtCellSt: + case xlsb_type::BrtFmlaString: { + if (!in_sheet_data) + break; + + if (d.size() < offsetof(brt_cell_st, str)) + Rcpp::stop("Malformed BrtCellSt record."); + + const auto& h = *(brt_cell_st*)d.data(); + + if (d.size() < offsetof(brt_cell_st, str) + (h.len * sizeof(char16_t))) + Rcpp::stop("Malformed BrtCellSt record."); + + if (h.cell.column < last_col) + Rcpp::stop("Cells out of order."); + + while (last_col < h.cell.column) { + row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + last_col++; + } + + last_col = h.cell.column + 1; + + auto number_format = find_number_format(h.cell.iStyleRef); + + auto u16sv = u16string_view(h.str, h.len); + + auto c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + + // so we don't have to expose shared_string publicly + c->impl->val = utf16_to_utf8(u16sv); + c->impl->number_format = number_format; + + break; + } + + case xlsb_type::BrtCellIsst: { + if (!in_sheet_data) + break; + + if (d.size() < sizeof(brt_cell_isst)) + Rcpp::stop("Malformed BrtCellIsst record."); + + const auto& h = *(brt_cell_isst*)d.data(); + + if (h.cell.column < last_col) + Rcpp::stop("Cells out of order."); + + while (last_col < h.cell.column) { + row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + last_col++; + } + + last_col = h.cell.column + 1; + + auto number_format = find_number_format(h.cell.iStyleRef); + + shared_string ss; + ss.num = h.isst; + + auto c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + + // so we don't have to expose shared_string publicly + delete c->impl; + c->impl = new cell_pimpl(*row->impl, (unsigned int)row->impl->cells.size(), ss); + + c->impl->number_format = number_format; + + break; + } + + case xlsb_type::BrtCellRString: { + if (!in_sheet_data) + break; + + if (d.size() < offsetof(brt_cell_rstring, value.str)) + Rcpp::stop("Malformed BrtCellRString record."); + + const auto& h = *(brt_cell_rstring*)d.data(); + + if (d.size() < offsetof(brt_cell_rstring, value.str) + (h.value.len * sizeof(char16_t))) + Rcpp::stop("Malformed BrtCellRString record."); + + if (h.cell.column < last_col) + Rcpp::stop("Cells out of order."); + + while (last_col < h.cell.column) { + row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + last_col++; + } + + last_col = h.cell.column + 1; + + auto number_format = find_number_format(h.cell.iStyleRef); + + auto u16sv = u16string_view(h.value.str, h.value.len); + + auto c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); + + // so we don't have to expose shared_string publicly + c->impl->val = utf16_to_utf8(u16sv); + + c->impl->number_format = number_format; + + break; + } + + default: + break; + } + }); +} + +void workbook_pimpl::parse_workbook_binary(string_view fn, span data, const unordered_map& files) { + struct sheet_info { + sheet_info(string_view rid, string_view name, bool visible) : + rid(rid), name(name), visible(visible) { } + + string rid; + string name; + bool visible; + }; + + vector sheets_rels; + + xlsb_walk(data, [&](enum xlsb_type type, span d) { + switch (type) { + case xlsb_type::BrtBundleSh: { + if (d.size() < sizeof(brt_bundle_sh)) + Rcpp::stop("Malformed BrtBundleSh entry."); + + auto& h = *(brt_bundle_sh*)d.data(); + + d = d.subspan(sizeof(brt_bundle_sh)); + + if (d.size() < sizeof(uint32_t)) + Rcpp::stop("Malformed BrtBundleSh entry."); + + auto relid_size = *(uint32_t*)d.data(); + + d = d.subspan(sizeof(uint32_t)); + + if (relid_size == 0xffffffff) + relid_size = 0; + + if (d.size() < relid_size * sizeof(char16_t)) + Rcpp::stop("Malformed BrtBundleSh entry."); + + auto strRelID = u16string_view((char16_t*)d.data(), relid_size); + + d = d.subspan(relid_size * sizeof(char16_t)); + + if (d.size() < sizeof(uint32_t)) + Rcpp::stop("Malformed BrtBundleSh entry."); + + auto name_size = *(uint32_t*)d.data(); + + d = d.subspan(sizeof(uint32_t)); + + if (d.size() < name_size * sizeof(char16_t)) + Rcpp::stop("Malformed BrtBundleSh entry."); + + auto strName = u16string_view((char16_t*)d.data(), name_size); + + sheets_rels.emplace_back(utf16_to_utf8(strRelID), utf16_to_utf8(strName), h.hsState == 0); + + break; + } + + case xlsb_type::BrtWbProp: { + if (d.size() < sizeof(brt_wb_prop)) + Rcpp::stop("Malformed BrtWbProp entry."); + + const auto& h = *(brt_wb_prop*)d.data(); + + date1904 = h.f1904; + + break; + } + + default: + break; + } + }); + + // FIXME - preserve sheet order + + auto rels = read_relationships(fn, files); + + for (const auto& sr : sheets_rels) { + for (const auto& r : rels) { + if (r.first == sr.rid) { + auto name = filesystem::path(fn); + + // FIXME - can we resolve relative paths properly? + + name.remove_filename(); + name /= r.second; + + auto ns = name.string(); + + for (auto& c : ns) { + if (c == '\\') + c = '/'; + } + + if (files.count(ns) == 0) + Rcpp::stop("File {} not found.", ns); + + auto& d = files.at(ns).data; + + load_sheet_binary(sr.name, span((uint8_t*)d.data(), d.size()), sr.visible); + break; + } + } + } +} + +void workbook_pimpl::load_shared_strings_binary(span data) { + xlsb_walk(data, [&](enum xlsb_type type, span d) { + if (type == xlsb_type::BrtSSTItem) { + if (d.size() < offsetof(brt_sst_item, richStr.str)) + Rcpp::stop("Malformed BrtSSTItem record."); + + const auto& h = *(brt_sst_item*)d.data(); + + if (d.size() < offsetof(brt_sst_item, richStr.str) + (sizeof(char16_t) * h.richStr.len)) + Rcpp::stop("Malformed BrtSSTItem record."); + + auto u16sv = u16string_view(h.richStr.str, h.richStr.len); + + shared_strings2.emplace_back(utf16_to_utf8(u16sv)); + } + }); +} + +void workbook_pimpl::load_styles_binary(span data) { + bool in_numfmts = false, in_cellxfs = false; + + xlsb_walk(data, [&](enum xlsb_type type, span d) { + switch (type) { + case xlsb_type::BrtBeginCellXFs: + in_cellxfs = true; + break; + + case xlsb_type::BrtEndCellXFs: + in_cellxfs = false; + break; + + case xlsb_type::BrtBeginFmts: + in_numfmts = true; + break; + + case xlsb_type::BrtEndFmts: + in_numfmts = false; + break; + + case xlsb_type::BrtXF: + if (in_cellxfs) { + optional numfmtid; + + if (d.size() < sizeof(brt_xf)) + Rcpp::stop("Malformed BrtXF record."); + + const auto& h = *(brt_xf*)d.data(); + + numfmtid = h.iFmt; + + if (h.xfGrbitAtr & 1) + numfmtid = nullopt; + + cell_styles.push_back(numfmtid); + } + break; + + case xlsb_type::BrtFmt: + if (in_numfmts) { + if (d.size() < offsetof(brt_fmt, stFmtCode)) + Rcpp::stop("Malformed BrtFmt record."); + + const auto& h = *(brt_fmt*)d.data(); + + if (d.size() < offsetof(brt_fmt, stFmtCode) + (h.stFmtCode_len * sizeof(char16_t))) + Rcpp::stop("Malformed BrtFmt record."); + + auto u16sv = u16string_view(h.stFmtCode, h.stFmtCode_len); + auto s = utf16_to_utf8(u16sv); + + // FIXME - removing backslashes? + + number_formats[h.ifmt] = s; + } + break; + + default: + break; + } + }); +} + +}; diff --git a/src/xlcpp/xlsb.h b/src/xlcpp/xlsb.h new file mode 100644 index 000000000..af02fd90d --- /dev/null +++ b/src/xlcpp/xlsb.h @@ -0,0 +1,2707 @@ +#pragma once + +enum class xlsb_type { + BrtRowHdr = 0, + BrtCellBlank = 1, + BrtCellRk = 2, + BrtCellError = 3, + BrtCellBool = 4, + BrtCellReal = 5, + BrtCellSt = 6, + BrtCellIsst = 7, + BrtFmlaString = 8, + BrtFmlaNum = 9, + BrtFmlaBool = 10, + BrtFmlaError = 11, + BrtSSTItem = 19, + BrtPCDIMissing = 20, + BrtPCDINumber = 21, + BrtPCDIBoolean = 22, + BrtPCDIError = 23, + BrtPCDIString = 24, + BrtPCDIDatetime = 25, + BrtPCDIIndex = 26, + BrtPCDIAMissing = 27, + BrtPCDIANumber = 28, + BrtPCDIABoolean = 29, + BrtPCDIAError = 30, + BrtPCDIAString = 31, + BrtPCDIADatetime = 32, + BrtPCRRecord = 33, + BrtPCRRecordDt = 34, + BrtFRTBegin = 35, + BrtFRTEnd = 36, + BrtACBegin = 37, + BrtACEnd = 38, + BrtName = 39, + BrtIndexRowBlock = 40, + BrtIndexBlock = 42, + BrtFont = 43, + BrtFmt = 44, + BrtFill = 45, + BrtBorder = 46, + BrtXF = 47, + BrtStyle = 48, + BrtCellMeta = 49, + BrtValueMeta = 50, + BrtMdb = 51, + BrtBeginFmd = 52, + BrtEndFmd = 53, + BrtBeginMdx = 54, + BrtEndMdx = 55, + BrtBeginMdxTuple = 56, + BrtEndMdxTuple = 57, + BrtMdxMbrIstr = 58, + BrtStr = 59, + BrtColInfo = 60, + BrtCellRString = 62, + BrtDVal = 64, + BrtSxvcellNum = 65, + BrtSxvcellStr = 66, + BrtSxvcellBool = 67, + BrtSxvcellErr = 68, + BrtSxvcellDate = 69, + BrtSxvcellNil = 70, + BrtFileVersion = 128, + BrtBeginSheet = 129, + BrtEndSheet = 130, + BrtBeginBook = 131, + BrtEndBook = 132, + BrtBeginWsViews = 133, + BrtEndWsViews = 134, + BrtBeginBookViews = 135, + BrtEndBookViews = 136, + BrtBeginWsView = 137, + BrtEndWsView = 138, + BrtBeginCsViews = 139, + BrtEndCsViews = 140, + BrtBeginCsView = 141, + BrtEndCsView = 142, + BrtBeginBundleShs = 143, + BrtEndBundleShs = 144, + BrtBeginSheetData = 145, + BrtEndSheetData = 146, + BrtWsProp = 147, + BrtWsDim = 148, + BrtPane = 151, + BrtSel = 152, + BrtWbProp = 153, + BrtWbFactoid = 154, + BrtFileRecover = 155, + BrtBundleSh = 156, + BrtCalcProp = 157, + BrtBookView = 158, + BrtBeginSst = 159, + BrtEndSst = 160, + BrtBeginAFilter = 161, + BrtEndAFilter = 162, + BrtBeginFilterColumn = 163, + BrtEndFilterColumn = 164, + BrtBeginFilters = 165, + BrtEndFilters = 166, + BrtFilter = 167, + BrtColorFilter = 168, + BrtIconFilter = 169, + BrtTop10Filter = 170, + BrtDynamicFilter = 171, + BrtBeginCustomFilters = 172, + BrtEndCustomFilters = 173, + BrtCustomFilter = 174, + BrtAFilterDateGroupItem = 175, + BrtMergeCell = 176, + BrtBeginMergeCells = 177, + BrtEndMergeCells = 178, + BrtBeginPivotCacheDef = 179, + BrtEndPivotCacheDef = 180, + BrtBeginPCDFields = 181, + BrtEndPCDFields = 182, + BrtBeginPCDField = 183, + BrtEndPCDField = 184, + BrtBeginPCDSource = 185, + BrtEndPCDSource = 186, + BrtBeginPCDSRange = 187, + BrtEndPCDSRange = 188, + BrtBeginPCDFAtbl = 189, + BrtEndPCDFAtbl = 190, + BrtBeginPCDIRun = 191, + BrtEndPCDIRun = 192, + BrtBeginPivotCacheRecords = 193, + BrtEndPivotCacheRecords = 194, + BrtBeginPCDHierarchies = 195, + BrtEndPCDHierarchies = 196, + BrtBeginPCDHierarchy = 197, + BrtEndPCDHierarchy = 198, + BrtBeginPCDHFieldsUsage = 199, + BrtEndPCDHFieldsUsage = 200, + BrtBeginExtConnection = 201, + BrtEndExtConnection = 202, + BrtBeginECDbProps = 203, + BrtEndECDbProps = 204, + BrtBeginECOlapProps = 205, + BrtEndECOlapProps = 206, + BrtBeginPCDSConsol = 207, + BrtEndPCDSConsol = 208, + BrtBeginPCDSCPages = 209, + BrtEndPCDSCPages = 210, + BrtBeginPCDSCPage = 211, + BrtEndPCDSCPage = 212, + BrtBeginPCDSCPItem = 213, + BrtEndPCDSCPItem = 214, + BrtBeginPCDSCSets = 215, + BrtEndPCDSCSets = 216, + BrtBeginPCDSCSet = 217, + BrtEndPCDSCSet = 218, + BrtBeginPCDFGroup = 219, + BrtEndPCDFGroup = 220, + BrtBeginPCDFGItems = 221, + BrtEndPCDFGItems = 222, + BrtBeginPCDFGRange = 223, + BrtEndPCDFGRange = 224, + BrtBeginPCDFGDiscrete = 225, + BrtEndPCDFGDiscrete = 226, + BrtBeginPCDSDTupleCache = 227, + BrtEndPCDSDTupleCache = 228, + BrtBeginPCDSDTCEntries = 229, + BrtEndPCDSDTCEntries = 230, + BrtBeginPCDSDTCEMembers = 231, + BrtEndPCDSDTCEMembers = 232, + BrtBeginPCDSDTCEMember = 233, + BrtEndPCDSDTCEMember = 234, + BrtBeginPCDSDTCQueries = 235, + BrtEndPCDSDTCQueries = 236, + BrtBeginPCDSDTCQuery = 237, + BrtEndPCDSDTCQuery = 238, + BrtBeginPCDSDTCSets = 239, + BrtEndPCDSDTCSets = 240, + BrtBeginPCDSDTCSet = 241, + BrtEndPCDSDTCSet = 242, + BrtBeginPCDCalcItems = 243, + BrtEndPCDCalcItems = 244, + BrtBeginPCDCalcItem = 245, + BrtEndPCDCalcItem = 246, + BrtBeginPRule = 247, + BrtEndPRule = 248, + BrtBeginPRFilters = 249, + BrtEndPRFilters = 250, + BrtBeginPRFilter = 251, + BrtEndPRFilter = 252, + BrtBeginPNames = 253, + BrtEndPNames = 254, + BrtBeginPName = 255, + BrtEndPName = 256, + BrtBeginPNPairs = 257, + BrtEndPNPairs = 258, + BrtBeginPNPair = 259, + BrtEndPNPair = 260, + BrtBeginECWebProps = 261, + BrtEndECWebProps = 262, + BrtBeginEcWpTables = 263, + BrtEndECWPTables = 264, + BrtBeginECParams = 265, + BrtEndECParams = 266, + BrtBeginECParam = 267, + BrtEndECParam = 268, + BrtBeginPCDKPIs = 269, + BrtEndPCDKPIs = 270, + BrtBeginPCDKPI = 271, + BrtEndPCDKPI = 272, + BrtBeginDims = 273, + BrtEndDims = 274, + BrtBeginDim = 275, + BrtEndDim = 276, + BrtIndexPartEnd = 277, + BrtBeginStyleSheet = 278, + BrtEndStyleSheet = 279, + BrtBeginSXView = 280, + BrtEndSXVI = 281, + BrtBeginSXVI = 282, + BrtBeginSXVIs = 283, + BrtEndSXVIs = 284, + BrtBeginSXVD = 285, + BrtEndSXVD = 286, + BrtBeginSXVDs = 287, + BrtEndSXVDs = 288, + BrtBeginSXPI = 289, + BrtEndSXPI = 290, + BrtBeginSXPIs = 291, + BrtEndSXPIs = 292, + BrtBeginSXDI = 293, + BrtEndSXDI = 294, + BrtBeginSXDIs = 295, + BrtEndSXDIs = 296, + BrtBeginSXLI = 297, + BrtEndSXLI = 298, + BrtBeginSXLIRws = 299, + BrtEndSXLIRws = 300, + BrtBeginSXLICols = 301, + BrtEndSXLICols = 302, + BrtBeginSXFormat = 303, + BrtEndSXFormat = 304, + BrtBeginSXFormats = 305, + BrtEndSxFormats = 306, + BrtBeginSxSelect = 307, + BrtEndSxSelect = 308, + BrtBeginISXVDRws = 309, + BrtEndISXVDRws = 310, + BrtBeginISXVDCols = 311, + BrtEndISXVDCols = 312, + BrtEndSXLocation = 313, + BrtBeginSXLocation = 314, + BrtEndSXView = 315, + BrtBeginSXTHs = 316, + BrtEndSXTHs = 317, + BrtBeginSXTH = 318, + BrtEndSXTH = 319, + BrtBeginISXTHRws = 320, + BrtEndISXTHRws = 321, + BrtBeginISXTHCols = 322, + BrtEndISXTHCols = 323, + BrtBeginSXTDMPS = 324, + BrtEndSXTDMPs = 325, + BrtBeginSXTDMP = 326, + BrtEndSXTDMP = 327, + BrtBeginSXTHItems = 328, + BrtEndSXTHItems = 329, + BrtBeginSXTHItem = 330, + BrtEndSXTHItem = 331, + BrtBeginMetadata = 332, + BrtEndMetadata = 333, + BrtBeginEsmdtinfo = 334, + BrtMdtinfo = 335, + BrtEndEsmdtinfo = 336, + BrtBeginEsmdb = 337, + BrtEndEsmdb = 338, + BrtBeginEsfmd = 339, + BrtEndEsfmd = 340, + BrtBeginSingleCells = 341, + BrtEndSingleCells = 342, + BrtBeginList = 343, + BrtEndList = 344, + BrtBeginListCols = 345, + BrtEndListCols = 346, + BrtBeginListCol = 347, + BrtEndListCol = 348, + BrtBeginListXmlCPr = 349, + BrtEndListXmlCPr = 350, + BrtListCCFmla = 351, + BrtListTrFmla = 352, + BrtBeginExternals = 353, + BrtEndExternals = 354, + BrtSupBookSrc = 355, + BrtSupSelf = 357, + BrtSupSame = 358, + BrtSupTabs = 359, + BrtBeginSupBook = 360, + BrtPlaceholderName = 361, + BrtExternSheet = 362, + BrtExternTableStart = 363, + BrtExternTableEnd = 364, + BrtExternRowHdr = 366, + BrtExternCellBlank = 367, + BrtExternCellReal = 368, + BrtExternCellBool = 369, + BrtExternCellError = 370, + BrtExternCellString = 371, + BrtBeginEsmdx = 372, + BrtEndEsmdx = 373, + BrtBeginMdxSet = 374, + BrtEndMdxSet = 375, + BrtBeginMdxMbrProp = 376, + BrtEndMdxMbrProp = 377, + BrtBeginMdxKPI = 378, + BrtEndMdxKPI = 379, + BrtBeginEsstr = 380, + BrtEndEsstr = 381, + BrtBeginPRFItem = 382, + BrtEndPRFItem = 383, + BrtBeginPivotCacheIDs = 384, + BrtEndPivotCacheIDs = 385, + BrtBeginPivotCacheID = 386, + BrtEndPivotCacheID = 387, + BrtBeginISXVIs = 388, + BrtEndISXVIs = 389, + BrtBeginColInfos = 390, + BrtEndColInfos = 391, + BrtBeginRwBrk = 392, + BrtEndRwBrk = 393, + BrtBeginColBrk = 394, + BrtEndColBrk = 395, + BrtBrk = 396, + BrtUserBookView = 397, + BrtInfo = 398, + BrtCUsr = 399, + BrtUsr = 400, + BrtBeginUsers = 401, + BrtEOF = 403, + BrtUCR = 404, + BrtRRInsDel = 405, + BrtRREndInsDel = 406, + BrtRRMove = 407, + BrtRREndMove = 408, + BrtRRChgCell = 409, + BrtRREndChgCell = 410, + BrtRRHeader = 411, + BrtRRUserView = 412, + BrtRRRenSheet = 413, + BrtRRInsertSh = 414, + BrtRRDefName = 415, + BrtRRNote = 416, + BrtRRConflict = 417, + BrtRRTQSIF = 418, + BrtRRFormat = 419, + BrtRREndFormat = 420, + BrtRRAutoFmt = 421, + BrtBeginUserShViews = 422, + BrtBeginUserShView = 423, + BrtEndUserShView = 424, + BrtEndUserShViews = 425, + BrtArrFmla = 426, + BrtShrFmla = 427, + BrtTable = 428, + BrtBeginExtConnections = 429, + BrtEndExtConnections = 430, + BrtBeginPCDCalcMems = 431, + BrtEndPCDCalcMems = 432, + BrtBeginPCDCalcMem = 433, + BrtEndPCDCalcMem = 434, + BrtBeginPCDHGLevels = 435, + BrtEndPCDHGLevels = 436, + BrtBeginPCDHGLevel = 437, + BrtEndPCDHGLevel = 438, + BrtBeginPCDHGLGroups = 439, + BrtEndPCDHGLGroups = 440, + BrtBeginPCDHGLGroup = 441, + BrtEndPCDHGLGroup = 442, + BrtBeginPCDHGLGMembers = 443, + BrtEndPCDHGLGMembers = 444, + BrtBeginPCDHGLGMember = 445, + BrtEndPCDHGLGMember = 446, + BrtBeginQSI = 447, + BrtEndQSI = 448, + BrtBeginQSIR = 449, + BrtEndQSIR = 450, + BrtBeginDeletedNames = 451, + BrtEndDeletedNames = 452, + BrtBeginDeletedName = 453, + BrtEndDeletedName = 454, + BrtBeginQSIFs = 455, + BrtEndQSIFs = 456, + BrtBeginQSIF = 457, + BrtEndQSIF = 458, + BrtBeginAutoSortScope = 459, + BrtEndAutoSortScope = 460, + BrtBeginConditionalFormatting = 461, + BrtEndConditionalFormatting = 462, + BrtBeginCFRule = 463, + BrtEndCFRule = 464, + BrtBeginIconSet = 465, + BrtEndIconSet = 466, + BrtBeginDatabar = 467, + BrtEndDatabar = 468, + BrtBeginColorScale = 469, + BrtEndColorScale = 470, + BrtCFVO = 471, + BrtExternValueMeta = 472, + BrtBeginColorPalette = 473, + BrtEndColorPalette = 474, + BrtIndexedColor = 475, + BrtMargins = 476, + BrtPrintOptions = 477, + BrtPageSetup = 478, + BrtBeginHeaderFooter = 479, + BrtEndHeaderFooter = 480, + BrtBeginSXCrtFormat = 481, + BrtEndSXCrtFormat = 482, + BrtBeginSXCrtFormats = 483, + BrtEndSXCrtFormats = 484, + BrtWsFmtInfo = 485, + BrtBeginMgs = 486, + BrtEndMGs = 487, + BrtBeginMGMaps = 488, + BrtEndMGMaps = 489, + BrtBeginMG = 490, + BrtEndMG = 491, + BrtBeginMap = 492, + BrtEndMap = 493, + BrtHLink = 494, + BrtBeginDCon = 495, + BrtEndDCon = 496, + BrtBeginDRefs = 497, + BrtEndDRefs = 498, + BrtDRef = 499, + BrtBeginScenMan = 500, + BrtEndScenMan = 501, + BrtBeginSct = 502, + BrtEndSct = 503, + BrtSlc = 504, + BrtBeginDXFs = 505, + BrtEndDXFs = 506, + BrtDXF = 507, + BrtBeginTableStyles = 508, + BrtEndTableStyles = 509, + BrtBeginTableStyle = 510, + BrtEndTableStyle = 511, + BrtTableStyleElement = 512, + BrtTableStyleClient = 513, + BrtBeginVolDeps = 514, + BrtEndVolDeps = 515, + BrtBeginVolType = 516, + BrtEndVolType = 517, + BrtBeginVolMain = 518, + BrtEndVolMain = 519, + BrtBeginVolTopic = 520, + BrtEndVolTopic = 521, + BrtVolSubtopic = 522, + BrtVolRef = 523, + BrtVolNum = 524, + BrtVolErr = 525, + BrtVolStr = 526, + BrtVolBool = 527, + BrtBeginSortState = 530, + BrtEndSortState = 531, + BrtBeginSortCond = 532, + BrtEndSortCond = 533, + BrtBookProtection = 534, + BrtSheetProtection = 535, + BrtRangeProtection = 536, + BrtPhoneticInfo = 537, + BrtBeginECTxtWiz = 538, + BrtEndECTxtWiz = 539, + BrtBeginECTWFldInfoLst = 540, + BrtEndECTWFldInfoLst = 541, + BrtBeginECTwFldInfo = 542, + BrtFileSharing = 548, + BrtOleSize = 549, + BrtDrawing = 550, + BrtLegacyDrawing = 551, + BrtLegacyDrawingHF = 552, + BrtWebOpt = 553, + BrtBeginWebPubItems = 554, + BrtEndWebPubItems = 555, + BrtBeginWebPubItem = 556, + BrtEndWebPubItem = 557, + BrtBeginSXCondFmt = 558, + BrtEndSXCondFmt = 559, + BrtBeginSXCondFmts = 560, + BrtEndSXCondFmts = 561, + BrtBkHim = 562, + BrtColor = 564, + BrtBeginIndexedColors = 565, + BrtEndIndexedColors = 566, + BrtBeginMRUColors = 569, + BrtEndMRUColors = 570, + BrtMRUColor = 572, + BrtBeginDVals = 573, + BrtEndDVals = 574, + BrtSupNameStart = 577, + BrtSupNameValueStart = 578, + BrtSupNameValueEnd = 579, + BrtSupNameNum = 580, + BrtSupNameErr = 581, + BrtSupNameSt = 582, + BrtSupNameNil = 583, + BrtSupNameBool = 584, + BrtSupNameFmla = 585, + BrtSupNameBits = 586, + BrtSupNameEnd = 587, + BrtEndSupBook = 588, + BrtCellSmartTagProperty = 589, + BrtBeginCellSmartTag = 590, + BrtEndCellSmartTag = 591, + BrtBeginCellSmartTags = 592, + BrtEndCellSmartTags = 593, + BrtBeginSmartTags = 594, + BrtEndSmartTags = 595, + BrtSmartTagType = 596, + BrtBeginSmartTagTypes = 597, + BrtEndSmartTagTypes = 598, + BrtBeginSXFilters = 599, + BrtEndSXFilters = 600, + BrtBeginSXFILTER = 601, + BrtEndSXFilter = 602, + BrtBeginFills = 603, + BrtEndFills = 604, + BrtBeginCellWatches = 605, + BrtEndCellWatches = 606, + BrtCellWatch = 607, + BrtBeginCRErrs = 608, + BrtEndCRErrs = 609, + BrtCrashRecErr = 610, + BrtBeginFonts = 611, + BrtEndFonts = 612, + BrtBeginBorders = 613, + BrtEndBorders = 614, + BrtBeginFmts = 615, + BrtEndFmts = 616, + BrtBeginCellXFs = 617, + BrtEndCellXFs = 618, + BrtBeginStyles = 619, + BrtEndStyles = 620, + BrtBigName = 625, + BrtBeginCellStyleXFs = 626, + BrtEndCellStyleXFs = 627, + BrtBeginComments = 628, + BrtEndComments = 629, + BrtBeginCommentAuthors = 630, + BrtEndCommentAuthors = 631, + BrtCommentAuthor = 632, + BrtBeginCommentList = 633, + BrtEndCommentList = 634, + BrtBeginComment = 635, + BrtEndComment = 636, + BrtCommentText = 637, + BrtBeginOleObjects = 638, + BrtOleObject = 639, + BrtEndOleObjects = 640, + BrtBeginSxrules = 641, + BrtEndSxRules = 642, + BrtBeginActiveXControls = 643, + BrtActiveX = 644, + BrtEndActiveXControls = 645, + BrtBeginPCDSDTCEMembersSortBy = 646, + BrtBeginCellIgnoreECs = 648, + BrtCellIgnoreEC = 649, + BrtEndCellIgnoreECs = 650, + BrtCsProp = 651, + BrtCsPageSetup = 652, + BrtBeginUserCsViews = 653, + BrtEndUserCsViews = 654, + BrtBeginUserCsView = 655, + BrtEndUserCsView = 656, + BrtBeginPcdSFCIEntries = 657, + BrtEndPCDSFCIEntries = 658, + BrtPCDSFCIEntry = 659, + BrtBeginListParts = 660, + BrtListPart = 661, + BrtEndListParts = 662, + BrtSheetCalcProp = 663, + BrtBeginFnGroup = 664, + BrtFnGroup = 665, + BrtEndFnGroup = 666, + BrtSupAddin = 667, + BrtSXTDMPOrder = 668, + BrtCsProtection = 669, + BrtBeginWsSortMap = 671, + BrtEndWsSortMap = 672, + BrtBeginRRSort = 673, + BrtEndRRSort = 674, + BrtRRSortItem = 675, + BrtFileSharingIso = 676, + BrtBookProtectionIso = 677, + BrtSheetProtectionIso = 678, + BrtCsProtectionIso = 679, + BrtRangeProtectionIso = 680, + BrtDValList = 681, + BrtRwDescent = 1024, + BrtKnownFonts = 1025, + BrtBeginSXTupleSet = 1026, + BrtEndSXTupleSet = 1027, + BrtBeginSXTupleSetHeader = 1028, + BrtEndSXTupleSetHeader = 1029, + BrtSXTupleSetHeaderItem = 1030, + BrtBeginSXTupleSetData = 1031, + BrtEndSXTupleSetData = 1032, + BrtBeginSXTupleSetRow = 1033, + BrtEndSXTupleSetRow = 1034, + BrtSXTupleSetRowItem = 1035, + BrtNameExt = 1036, + BrtPCDH14 = 1037, + BrtBeginPCDCalcMem14 = 1038, + BrtEndPCDCalcMem14 = 1039, + BrtSXTH14 = 1040, + BrtBeginSparklineGroup = 1041, + BrtEndSparklineGroup = 1042, + BrtSparkline = 1043, + BrtSXDI14 = 1044, + BrtWsFmtInfoEx14 = 1045, + BrtBeginConditionalFormatting14 = 1046, + BrtEndConditionalFormatting14 = 1047, + BrtBeginCFRule14 = 1048, + BrtEndCFRule14 = 1049, + BrtCFVO14 = 1050, + BrtBeginDatabar14 = 1051, + BrtBeginIconSet14 = 1052, + BrtDVal14 = 1053, + BrtBeginDVals14 = 1054, + BrtColor14 = 1055, + BrtBeginSparklines = 1056, + BrtEndSparklines = 1057, + BrtBeginSparklineGroups = 1058, + BrtEndSparklineGroups = 1059, + BrtSXVD14 = 1061, + BrtBeginSxView14 = 1062, + BrtEndSxView14 = 1063, + BrtBeginSXView16 = 1064, + BrtEndSXView16 = 1065, + BrtBeginPCD14 = 1066, + BrtEndPCD14 = 1067, + BrtBeginExtConn14 = 1068, + BrtEndExtConn14 = 1069, + BrtBeginSlicerCacheIDs = 1070, + BrtEndSlicerCacheIDs = 1071, + BrtBeginSlicerCacheID = 1072, + BrtEndSlicerCacheID = 1073, + BrtBeginSlicerCache = 1075, + BrtEndSlicerCache = 1076, + BrtBeginSlicerCacheDef = 1077, + BrtEndSlicerCacheDef = 1078, + BrtBeginSlicersEx = 1079, + BrtEndSlicersEx = 1080, + BrtBeginSlicerEx = 1081, + BrtEndSlicerEx = 1082, + BrtBeginSlicer = 1083, + BrtEndSlicer = 1084, + BrtSlicerCachePivotTables = 1085, + BrtBeginSlicerCacheOlapImpl = 1086, + BrtEndSlicerCacheOlapImpl = 1087, + BrtBeginSlicerCacheLevelsData = 1088, + BrtEndSlicerCacheLevelsData = 1089, + BrtBeginSlicerCacheLevelData = 1090, + BrtEndSlicerCacheLevelData = 1091, + BrtBeginSlicerCacheSiRanges = 1092, + BrtEndSlicerCacheSiRanges = 1093, + BrtBeginSlicerCacheSiRange = 1094, + BrtEndSlicerCacheSiRange = 1095, + BrtSlicerCacheOlapItem = 1096, + BrtBeginSlicerCacheSelections = 1097, + BrtSlicerCacheSelection = 1098, + BrtEndSlicerCacheSelections = 1099, + BrtBeginSlicerCacheNative = 1100, + BrtEndSlicerCacheNative = 1101, + BrtSlicerCacheNativeItem = 1102, + BrtRangeProtection14 = 1103, + BrtRangeProtectionIso14 = 1104, + BrtCellIgnoreEC14 = 1105, + BrtList14 = 1111, + BrtCFIcon = 1112, + BrtBeginSlicerCachesPivotCacheIDs = 1113, + BrtEndSlicerCachesPivotCacheIDs = 1114, + BrtBeginSlicers = 1115, + BrtEndSlicers = 1116, + BrtWbProp14 = 1117, + BrtBeginSXEdit = 1118, + BrtEndSXEdit = 1119, + BrtBeginSXEdits = 1120, + BrtEndSXEdits = 1121, + BrtBeginSXChange = 1122, + BrtEndSXChange = 1123, + BrtBeginSXChanges = 1124, + BrtEndSXChanges = 1125, + BrtSXTupleItems = 1126, + BrtBeginSlicerStyle = 1128, + BrtEndSlicerStyle = 1129, + BrtSlicerStyleElement = 1130, + BrtBeginStyleSheetExt14 = 1131, + BrtEndStyleSheetExt14 = 1132, + BrtBeginSlicerCachesPivotCacheID = 1133, + BrtEndSlicerCachesPivotCacheID = 1134, + BrtBeginConditionalFormattings = 1135, + BrtEndConditionalFormattings = 1136, + BrtBeginPCDCalcMemExt = 1137, + BrtEndPCDCalcMemExt = 1138, + BrtBeginPCDCalcMemsExt = 1139, + BrtEndPCDCalcMemsExt = 1140, + BrtPCDField14 = 1141, + BrtBeginSlicerStyles = 1142, + BrtEndSlicerStyles = 1143, + BrtBeginSlicerStyleElements = 1144, + BrtEndSlicerStyleElements = 1145, + BrtCFRuleExt = 1146, + BrtBeginSXCondFmt14 = 1147, + BrtEndSXCondFmt14 = 1148, + BrtBeginSXCondFmts14 = 1149, + BrtEndSXCondFmts14 = 1150, + BrtBeginSortCond14 = 1152, + BrtEndSortCond14 = 1153, + BrtEndDVals14 = 1154, + BrtEndIconSet14 = 1155, + BrtEndDatabar14 = 1156, + BrtBeginColorScale14 = 1157, + BrtEndColorScale14 = 1158, + BrtBeginSxrules14 = 1159, + BrtEndSxrules14 = 1160, + BrtBeginPRule14 = 1161, + BrtEndPRule14 = 1162, + BrtBeginPRFilters14 = 1163, + BrtEndPRFilters14 = 1164, + BrtBeginPRFilter14 = 1165, + BrtEndPRFilter14 = 1166, + BrtBeginPRFItem14 = 1167, + BrtEndPRFItem14 = 1168, + BrtBeginCellIgnoreECs14 = 1169, + BrtEndCellIgnoreECs14 = 1170, + BrtDxf14 = 1171, + BrtBeginDxF14s = 1172, + BrtEndDxf14s = 1173, + BrtFilter14 = 1177, + BrtBeginCustomFilters14 = 1178, + BrtCustomFilter14 = 1180, + BrtIconFilter14 = 1181, + BrtPivotCacheConnectionName = 1182, + BrtBeginDecoupledPivotCacheIDs = 2048, + BrtEndDecoupledPivotCacheIDs = 2049, + BrtDecoupledPivotCacheID = 2050, + BrtBeginPivotTableRefs = 2051, + BrtEndPivotTableRefs = 2052, + BrtPivotTableRef = 2053, + BrtSlicerCacheBookPivotTables = 2054, + BrtBeginSxvcells = 2055, + BrtEndSxvcells = 2056, + BrtBeginSxRow = 2057, + BrtEndSxRow = 2058, + BrtPcdCalcMem15 = 2060, + BrtQsi15 = 2067, + BrtBeginWebExtensions = 2068, + BrtEndWebExtensions = 2069, + BrtWebExtension = 2070, + BrtAbsPath15 = 2071, + BrtBeginPivotTableUISettings = 2072, + BrtEndPivotTableUISettings = 2073, + BrtTableSlicerCacheIDs = 2075, + BrtTableSlicerCacheID = 2076, + BrtBeginTableSlicerCache = 2077, + BrtEndTableSlicerCache = 2078, + BrtSxFilter15 = 2079, + BrtBeginTimelineCachePivotCacheIDs = 2080, + BrtEndTimelineCachePivotCacheIDs = 2081, + BrtTimelineCachePivotCacheID = 2082, + BrtBeginTimelineCacheIDs = 2083, + BrtEndTimelineCacheIDs = 2084, + BrtBeginTimelineCacheID = 2085, + BrtEndTimelineCacheID = 2086, + BrtBeginTimelinesEx = 2087, + BrtEndTimelinesEx = 2088, + BrtBeginTimelineEx = 2089, + BrtEndTimelineEx = 2090, + BrtWorkBookPr15 = 2091, + BrtPCDH15 = 2092, + BrtBeginTimelineStyle = 2093, + BrtEndTimelineStyle = 2094, + BrtTimelineStyleElement = 2095, + BrtBeginTimelineStylesheetExt15 = 2096, + BrtEndTimelineStylesheetExt15 = 2097, + BrtBeginTimelineStyles = 2098, + BrtEndTimelineStyles = 2099, + BrtBeginTimelineStyleElements = 2100, + BrtEndTimelineStyleElements = 2101, + BrtDxf15 = 2102, + BrtBeginDxfs15 = 2103, + BrtEndDXFs15 = 2104, + BrtSlicerCacheHideItemsWithNoData = 2105, + BrtBeginItemUniqueNames = 2106, + BrtEndItemUniqueNames = 2107, + BrtItemUniqueName = 2108, + BrtBeginExtConn15 = 2109, + BrtEndExtConn15 = 2110, + BrtBeginOledbPr15 = 2111, + BrtEndOledbPr15 = 2112, + BrtBeginDataFeedPr15 = 2113, + BrtEndDataFeedPr15 = 2114, + BrtTextPr15 = 2115, + BrtRangePr15 = 2116, + BrtDbCommand15 = 2117, + BrtBeginDbTables15 = 2118, + BrtEndDbTables15 = 2119, + BrtDbTable15 = 2120, + BrtBeginDataModel = 2121, + BrtEndDataModel = 2122, + BrtBeginModelTables = 2123, + BrtEndModelTables = 2124, + BrtModelTable = 2125, + BrtBeginModelRelationships = 2126, + BrtEndModelRelationships = 2127, + BrtModelRelationship = 2128, + BrtBeginECTxtWiz15 = 2129, + BrtEndECTxtWiz15 = 2130, + BrtBeginECTWFldInfoLst15 = 2131, + BrtEndECTWFldInfoLst15 = 2132, + BrtBeginECTWFldInfo15 = 2133, + BrtFieldListActiveItem = 2134, + BrtPivotCacheIdVersion = 2135, + BrtSXDI15 = 2136, + brtBeginModelTimeGroupings = 2137, + brtEndModelTimeGroupings = 2138, + brtBeginModelTimeGrouping = 2139, + brtEndModelTimeGrouping = 2140, + brtModelTimeGroupingCalcCol = 2141, + brtRevisionPtr = 3073, + BrtBeginDynamicArrayPr = 4096, + BrtEndDynamicArrayPr = 4097, + BrtBeginRichValueBlock = 5002, + BrtEndRichValueBlock = 5003, + BrtBeginRichFilters = 5081, + BrtEndRichFilters = 5082, + BrtRichFilter = 5083, + BrtBeginRichFilterColumn = 5084, + BrtEndRichFilterColumn = 5085, + BrtBeginCustomRichFilters = 5086, + BrtEndCustomRichFilters = 5087, + BRTCustomRichFilter = 5088, + BrtTop10RichFilter = 5089, + BrtDynamicRichFilter = 5090, + BrtBeginRichSortCondition = 5092, + BrtEndRichSortCondition = 5093, + BrtRichFilterDateGroupItem = 5094, + BrtBeginCalcFeatures = 5095, + BrtEndCalcFeatures = 5096, + BrtCalcFeature = 5097, + BrtExternalLinksPr = 5099 +}; + +template<> +struct fmt::formatter { + constexpr auto parse(format_parse_context& ctx) { + auto it = ctx.begin(); + + if (it != ctx.end() && *it != '}') + throw format_error("invalid format"); + + return it; + } + + template + auto format(enum xlsb_type t, format_context& ctx) const { + switch (t) { + case xlsb_type::BrtRowHdr: + return fmt::format_to(ctx.out(), "BrtRowHdr"); + case xlsb_type::BrtCellBlank: + return fmt::format_to(ctx.out(), "BrtCellBlank"); + case xlsb_type::BrtCellRk: + return fmt::format_to(ctx.out(), "BrtCellRk"); + case xlsb_type::BrtCellError: + return fmt::format_to(ctx.out(), "BrtCellError"); + case xlsb_type::BrtCellBool: + return fmt::format_to(ctx.out(), "BrtCellBool"); + case xlsb_type::BrtCellReal: + return fmt::format_to(ctx.out(), "BrtCellReal"); + case xlsb_type::BrtCellSt: + return fmt::format_to(ctx.out(), "BrtCellSt"); + case xlsb_type::BrtCellIsst: + return fmt::format_to(ctx.out(), "BrtCellIsst"); + case xlsb_type::BrtFmlaString: + return fmt::format_to(ctx.out(), "BrtFmlaString"); + case xlsb_type::BrtFmlaNum: + return fmt::format_to(ctx.out(), "BrtFmlaNum"); + case xlsb_type::BrtFmlaBool: + return fmt::format_to(ctx.out(), "BrtFmlaBool"); + case xlsb_type::BrtFmlaError: + return fmt::format_to(ctx.out(), "BrtFmlaError"); + case xlsb_type::BrtSSTItem: + return fmt::format_to(ctx.out(), "BrtSSTItem"); + case xlsb_type::BrtPCDIMissing: + return fmt::format_to(ctx.out(), "BrtPCDIMissing"); + case xlsb_type::BrtPCDINumber: + return fmt::format_to(ctx.out(), "BrtPCDINumber"); + case xlsb_type::BrtPCDIBoolean: + return fmt::format_to(ctx.out(), "BrtPCDIBoolean"); + case xlsb_type::BrtPCDIError: + return fmt::format_to(ctx.out(), "BrtPCDIError"); + case xlsb_type::BrtPCDIString: + return fmt::format_to(ctx.out(), "BrtPCDIString"); + case xlsb_type::BrtPCDIDatetime: + return fmt::format_to(ctx.out(), "BrtPCDIDatetime"); + case xlsb_type::BrtPCDIIndex: + return fmt::format_to(ctx.out(), "BrtPCDIIndex"); + case xlsb_type::BrtPCDIAMissing: + return fmt::format_to(ctx.out(), "BrtPCDIAMissing"); + case xlsb_type::BrtPCDIANumber: + return fmt::format_to(ctx.out(), "BrtPCDIANumber"); + case xlsb_type::BrtPCDIABoolean: + return fmt::format_to(ctx.out(), "BrtPCDIABoolean"); + case xlsb_type::BrtPCDIAError: + return fmt::format_to(ctx.out(), "BrtPCDIAError"); + case xlsb_type::BrtPCDIAString: + return fmt::format_to(ctx.out(), "BrtPCDIAString"); + case xlsb_type::BrtPCDIADatetime: + return fmt::format_to(ctx.out(), "BrtPCDIADatetime"); + case xlsb_type::BrtPCRRecord: + return fmt::format_to(ctx.out(), "BrtPCRRecord"); + case xlsb_type::BrtPCRRecordDt: + return fmt::format_to(ctx.out(), "BrtPCRRecordDt"); + case xlsb_type::BrtFRTBegin: + return fmt::format_to(ctx.out(), "BrtFRTBegin"); + case xlsb_type::BrtFRTEnd: + return fmt::format_to(ctx.out(), "BrtFRTEnd"); + case xlsb_type::BrtACBegin: + return fmt::format_to(ctx.out(), "BrtACBegin"); + case xlsb_type::BrtACEnd: + return fmt::format_to(ctx.out(), "BrtACEnd"); + case xlsb_type::BrtName: + return fmt::format_to(ctx.out(), "BrtName"); + case xlsb_type::BrtIndexRowBlock: + return fmt::format_to(ctx.out(), "BrtIndexRowBlock"); + case xlsb_type::BrtIndexBlock: + return fmt::format_to(ctx.out(), "BrtIndexBlock"); + case xlsb_type::BrtFont: + return fmt::format_to(ctx.out(), "BrtFont"); + case xlsb_type::BrtFmt: + return fmt::format_to(ctx.out(), "BrtFmt"); + case xlsb_type::BrtFill: + return fmt::format_to(ctx.out(), "BrtFill"); + case xlsb_type::BrtBorder: + return fmt::format_to(ctx.out(), "BrtBorder"); + case xlsb_type::BrtXF: + return fmt::format_to(ctx.out(), "BrtXF"); + case xlsb_type::BrtStyle: + return fmt::format_to(ctx.out(), "BrtStyle"); + case xlsb_type::BrtCellMeta: + return fmt::format_to(ctx.out(), "BrtCellMeta"); + case xlsb_type::BrtValueMeta: + return fmt::format_to(ctx.out(), "BrtValueMeta"); + case xlsb_type::BrtMdb: + return fmt::format_to(ctx.out(), "BrtMdb"); + case xlsb_type::BrtBeginFmd: + return fmt::format_to(ctx.out(), "BrtBeginFmd"); + case xlsb_type::BrtEndFmd: + return fmt::format_to(ctx.out(), "BrtEndFmd"); + case xlsb_type::BrtBeginMdx: + return fmt::format_to(ctx.out(), "BrtBeginMdx"); + case xlsb_type::BrtEndMdx: + return fmt::format_to(ctx.out(), "BrtEndMdx"); + case xlsb_type::BrtBeginMdxTuple: + return fmt::format_to(ctx.out(), "BrtBeginMdxTuple"); + case xlsb_type::BrtEndMdxTuple: + return fmt::format_to(ctx.out(), "BrtEndMdxTuple"); + case xlsb_type::BrtMdxMbrIstr: + return fmt::format_to(ctx.out(), "BrtMdxMbrIstr"); + case xlsb_type::BrtStr: + return fmt::format_to(ctx.out(), "BrtStr"); + case xlsb_type::BrtColInfo: + return fmt::format_to(ctx.out(), "BrtColInfo"); + case xlsb_type::BrtCellRString: + return fmt::format_to(ctx.out(), "BrtCellRString"); + case xlsb_type::BrtDVal: + return fmt::format_to(ctx.out(), "BrtDVal"); + case xlsb_type::BrtSxvcellNum: + return fmt::format_to(ctx.out(), "BrtSxvcellNum"); + case xlsb_type::BrtSxvcellStr: + return fmt::format_to(ctx.out(), "BrtSxvcellStr"); + case xlsb_type::BrtSxvcellBool: + return fmt::format_to(ctx.out(), "BrtSxvcellBool"); + case xlsb_type::BrtSxvcellErr: + return fmt::format_to(ctx.out(), "BrtSxvcellErr"); + case xlsb_type::BrtSxvcellDate: + return fmt::format_to(ctx.out(), "BrtSxvcellDate"); + case xlsb_type::BrtSxvcellNil: + return fmt::format_to(ctx.out(), "BrtSxvcellNil"); + case xlsb_type::BrtFileVersion: + return fmt::format_to(ctx.out(), "BrtFileVersion"); + case xlsb_type::BrtBeginSheet: + return fmt::format_to(ctx.out(), "BrtBeginSheet"); + case xlsb_type::BrtEndSheet: + return fmt::format_to(ctx.out(), "BrtEndSheet"); + case xlsb_type::BrtBeginBook: + return fmt::format_to(ctx.out(), "BrtBeginBook"); + case xlsb_type::BrtEndBook: + return fmt::format_to(ctx.out(), "BrtEndBook"); + case xlsb_type::BrtBeginWsViews: + return fmt::format_to(ctx.out(), "BrtBeginWsViews"); + case xlsb_type::BrtEndWsViews: + return fmt::format_to(ctx.out(), "BrtEndWsViews"); + case xlsb_type::BrtBeginBookViews: + return fmt::format_to(ctx.out(), "BrtBeginBookViews"); + case xlsb_type::BrtEndBookViews: + return fmt::format_to(ctx.out(), "BrtEndBookViews"); + case xlsb_type::BrtBeginWsView: + return fmt::format_to(ctx.out(), "BrtBeginWsView"); + case xlsb_type::BrtEndWsView: + return fmt::format_to(ctx.out(), "BrtEndWsView"); + case xlsb_type::BrtBeginCsViews: + return fmt::format_to(ctx.out(), "BrtBeginCsViews"); + case xlsb_type::BrtEndCsViews: + return fmt::format_to(ctx.out(), "BrtEndCsViews"); + case xlsb_type::BrtBeginCsView: + return fmt::format_to(ctx.out(), "BrtBeginCsView"); + case xlsb_type::BrtEndCsView: + return fmt::format_to(ctx.out(), "BrtEndCsView"); + case xlsb_type::BrtBeginBundleShs: + return fmt::format_to(ctx.out(), "BrtBeginBundleShs"); + case xlsb_type::BrtEndBundleShs: + return fmt::format_to(ctx.out(), "BrtEndBundleShs"); + case xlsb_type::BrtBeginSheetData: + return fmt::format_to(ctx.out(), "BrtBeginSheetData"); + case xlsb_type::BrtEndSheetData: + return fmt::format_to(ctx.out(), "BrtEndSheetData"); + case xlsb_type::BrtWsProp: + return fmt::format_to(ctx.out(), "BrtWsProp"); + case xlsb_type::BrtWsDim: + return fmt::format_to(ctx.out(), "BrtWsDim"); + case xlsb_type::BrtPane: + return fmt::format_to(ctx.out(), "BrtPane"); + case xlsb_type::BrtSel: + return fmt::format_to(ctx.out(), "BrtSel"); + case xlsb_type::BrtWbProp: + return fmt::format_to(ctx.out(), "BrtWbProp"); + case xlsb_type::BrtWbFactoid: + return fmt::format_to(ctx.out(), "BrtWbFactoid"); + case xlsb_type::BrtFileRecover: + return fmt::format_to(ctx.out(), "BrtFileRecover"); + case xlsb_type::BrtBundleSh: + return fmt::format_to(ctx.out(), "BrtBundleSh"); + case xlsb_type::BrtCalcProp: + return fmt::format_to(ctx.out(), "BrtCalcProp"); + case xlsb_type::BrtBookView: + return fmt::format_to(ctx.out(), "BrtBookView"); + case xlsb_type::BrtBeginSst: + return fmt::format_to(ctx.out(), "BrtBeginSst"); + case xlsb_type::BrtEndSst: + return fmt::format_to(ctx.out(), "BrtEndSst"); + case xlsb_type::BrtBeginAFilter: + return fmt::format_to(ctx.out(), "BrtBeginAFilter"); + case xlsb_type::BrtEndAFilter: + return fmt::format_to(ctx.out(), "BrtEndAFilter"); + case xlsb_type::BrtBeginFilterColumn: + return fmt::format_to(ctx.out(), "BrtBeginFilterColumn"); + case xlsb_type::BrtEndFilterColumn: + return fmt::format_to(ctx.out(), "BrtEndFilterColumn"); + case xlsb_type::BrtBeginFilters: + return fmt::format_to(ctx.out(), "BrtBeginFilters"); + case xlsb_type::BrtEndFilters: + return fmt::format_to(ctx.out(), "BrtEndFilters"); + case xlsb_type::BrtFilter: + return fmt::format_to(ctx.out(), "BrtFilter"); + case xlsb_type::BrtColorFilter: + return fmt::format_to(ctx.out(), "BrtColorFilter"); + case xlsb_type::BrtIconFilter: + return fmt::format_to(ctx.out(), "BrtIconFilter"); + case xlsb_type::BrtTop10Filter: + return fmt::format_to(ctx.out(), "BrtTop10Filter"); + case xlsb_type::BrtDynamicFilter: + return fmt::format_to(ctx.out(), "BrtDynamicFilter"); + case xlsb_type::BrtBeginCustomFilters: + return fmt::format_to(ctx.out(), "BrtBeginCustomFilters"); + case xlsb_type::BrtEndCustomFilters: + return fmt::format_to(ctx.out(), "BrtEndCustomFilters"); + case xlsb_type::BrtCustomFilter: + return fmt::format_to(ctx.out(), "BrtCustomFilter"); + case xlsb_type::BrtAFilterDateGroupItem: + return fmt::format_to(ctx.out(), "BrtAFilterDateGroupItem"); + case xlsb_type::BrtMergeCell: + return fmt::format_to(ctx.out(), "BrtMergeCell"); + case xlsb_type::BrtBeginMergeCells: + return fmt::format_to(ctx.out(), "BrtBeginMergeCells"); + case xlsb_type::BrtEndMergeCells: + return fmt::format_to(ctx.out(), "BrtEndMergeCells"); + case xlsb_type::BrtBeginPivotCacheDef: + return fmt::format_to(ctx.out(), "BrtBeginPivotCacheDef"); + case xlsb_type::BrtEndPivotCacheDef: + return fmt::format_to(ctx.out(), "BrtEndPivotCacheDef"); + case xlsb_type::BrtBeginPCDFields: + return fmt::format_to(ctx.out(), "BrtBeginPCDFields"); + case xlsb_type::BrtEndPCDFields: + return fmt::format_to(ctx.out(), "BrtEndPCDFields"); + case xlsb_type::BrtBeginPCDField: + return fmt::format_to(ctx.out(), "BrtBeginPCDField"); + case xlsb_type::BrtEndPCDField: + return fmt::format_to(ctx.out(), "BrtEndPCDField"); + case xlsb_type::BrtBeginPCDSource: + return fmt::format_to(ctx.out(), "BrtBeginPCDSource"); + case xlsb_type::BrtEndPCDSource: + return fmt::format_to(ctx.out(), "BrtEndPCDSource"); + case xlsb_type::BrtBeginPCDSRange: + return fmt::format_to(ctx.out(), "BrtBeginPCDSRange"); + case xlsb_type::BrtEndPCDSRange: + return fmt::format_to(ctx.out(), "BrtEndPCDSRange"); + case xlsb_type::BrtBeginPCDFAtbl: + return fmt::format_to(ctx.out(), "BrtBeginPCDFAtbl"); + case xlsb_type::BrtEndPCDFAtbl: + return fmt::format_to(ctx.out(), "BrtEndPCDFAtbl"); + case xlsb_type::BrtBeginPCDIRun: + return fmt::format_to(ctx.out(), "BrtBeginPCDIRun"); + case xlsb_type::BrtEndPCDIRun: + return fmt::format_to(ctx.out(), "BrtEndPCDIRun"); + case xlsb_type::BrtBeginPivotCacheRecords: + return fmt::format_to(ctx.out(), "BrtBeginPivotCacheRecords"); + case xlsb_type::BrtEndPivotCacheRecords: + return fmt::format_to(ctx.out(), "BrtEndPivotCacheRecords"); + case xlsb_type::BrtBeginPCDHierarchies: + return fmt::format_to(ctx.out(), "BrtBeginPCDHierarchies"); + case xlsb_type::BrtEndPCDHierarchies: + return fmt::format_to(ctx.out(), "BrtEndPCDHierarchies"); + case xlsb_type::BrtBeginPCDHierarchy: + return fmt::format_to(ctx.out(), "BrtBeginPCDHierarchy"); + case xlsb_type::BrtEndPCDHierarchy: + return fmt::format_to(ctx.out(), "BrtEndPCDHierarchy"); + case xlsb_type::BrtBeginPCDHFieldsUsage: + return fmt::format_to(ctx.out(), "BrtBeginPCDHFieldsUsage"); + case xlsb_type::BrtEndPCDHFieldsUsage: + return fmt::format_to(ctx.out(), "BrtEndPCDHFieldsUsage"); + case xlsb_type::BrtBeginExtConnection: + return fmt::format_to(ctx.out(), "BrtBeginExtConnection"); + case xlsb_type::BrtEndExtConnection: + return fmt::format_to(ctx.out(), "BrtEndExtConnection"); + case xlsb_type::BrtBeginECDbProps: + return fmt::format_to(ctx.out(), "BrtBeginECDbProps"); + case xlsb_type::BrtEndECDbProps: + return fmt::format_to(ctx.out(), "BrtEndECDbProps"); + case xlsb_type::BrtBeginECOlapProps: + return fmt::format_to(ctx.out(), "BrtBeginECOlapProps"); + case xlsb_type::BrtEndECOlapProps: + return fmt::format_to(ctx.out(), "BrtEndECOlapProps"); + case xlsb_type::BrtBeginPCDSConsol: + return fmt::format_to(ctx.out(), "BrtBeginPCDSConsol"); + case xlsb_type::BrtEndPCDSConsol: + return fmt::format_to(ctx.out(), "BrtEndPCDSConsol"); + case xlsb_type::BrtBeginPCDSCPages: + return fmt::format_to(ctx.out(), "BrtBeginPCDSCPages"); + case xlsb_type::BrtEndPCDSCPages: + return fmt::format_to(ctx.out(), "BrtEndPCDSCPages"); + case xlsb_type::BrtBeginPCDSCPage: + return fmt::format_to(ctx.out(), "BrtBeginPCDSCPage"); + case xlsb_type::BrtEndPCDSCPage: + return fmt::format_to(ctx.out(), "BrtEndPCDSCPage"); + case xlsb_type::BrtBeginPCDSCPItem: + return fmt::format_to(ctx.out(), "BrtBeginPCDSCPItem"); + case xlsb_type::BrtEndPCDSCPItem: + return fmt::format_to(ctx.out(), "BrtEndPCDSCPItem"); + case xlsb_type::BrtBeginPCDSCSets: + return fmt::format_to(ctx.out(), "BrtBeginPCDSCSets"); + case xlsb_type::BrtEndPCDSCSets: + return fmt::format_to(ctx.out(), "BrtEndPCDSCSets"); + case xlsb_type::BrtBeginPCDSCSet: + return fmt::format_to(ctx.out(), "BrtBeginPCDSCSet"); + case xlsb_type::BrtEndPCDSCSet: + return fmt::format_to(ctx.out(), "BrtEndPCDSCSet"); + case xlsb_type::BrtBeginPCDFGroup: + return fmt::format_to(ctx.out(), "BrtBeginPCDFGroup"); + case xlsb_type::BrtEndPCDFGroup: + return fmt::format_to(ctx.out(), "BrtEndPCDFGroup"); + case xlsb_type::BrtBeginPCDFGItems: + return fmt::format_to(ctx.out(), "BrtBeginPCDFGItems"); + case xlsb_type::BrtEndPCDFGItems: + return fmt::format_to(ctx.out(), "BrtEndPCDFGItems"); + case xlsb_type::BrtBeginPCDFGRange: + return fmt::format_to(ctx.out(), "BrtBeginPCDFGRange"); + case xlsb_type::BrtEndPCDFGRange: + return fmt::format_to(ctx.out(), "BrtEndPCDFGRange"); + case xlsb_type::BrtBeginPCDFGDiscrete: + return fmt::format_to(ctx.out(), "BrtBeginPCDFGDiscrete"); + case xlsb_type::BrtEndPCDFGDiscrete: + return fmt::format_to(ctx.out(), "BrtEndPCDFGDiscrete"); + case xlsb_type::BrtBeginPCDSDTupleCache: + return fmt::format_to(ctx.out(), "BrtBeginPCDSDTupleCache"); + case xlsb_type::BrtEndPCDSDTupleCache: + return fmt::format_to(ctx.out(), "BrtEndPCDSDTupleCache"); + case xlsb_type::BrtBeginPCDSDTCEntries: + return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCEntries"); + case xlsb_type::BrtEndPCDSDTCEntries: + return fmt::format_to(ctx.out(), "BrtEndPCDSDTCEntries"); + case xlsb_type::BrtBeginPCDSDTCEMembers: + return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCEMembers"); + case xlsb_type::BrtEndPCDSDTCEMembers: + return fmt::format_to(ctx.out(), "BrtEndPCDSDTCEMembers"); + case xlsb_type::BrtBeginPCDSDTCEMember: + return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCEMember"); + case xlsb_type::BrtEndPCDSDTCEMember: + return fmt::format_to(ctx.out(), "BrtEndPCDSDTCEMember"); + case xlsb_type::BrtBeginPCDSDTCQueries: + return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCQueries"); + case xlsb_type::BrtEndPCDSDTCQueries: + return fmt::format_to(ctx.out(), "BrtEndPCDSDTCQueries"); + case xlsb_type::BrtBeginPCDSDTCQuery: + return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCQuery"); + case xlsb_type::BrtEndPCDSDTCQuery: + return fmt::format_to(ctx.out(), "BrtEndPCDSDTCQuery"); + case xlsb_type::BrtBeginPCDSDTCSets: + return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCSets"); + case xlsb_type::BrtEndPCDSDTCSets: + return fmt::format_to(ctx.out(), "BrtEndPCDSDTCSets"); + case xlsb_type::BrtBeginPCDSDTCSet: + return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCSet"); + case xlsb_type::BrtEndPCDSDTCSet: + return fmt::format_to(ctx.out(), "BrtEndPCDSDTCSet"); + case xlsb_type::BrtBeginPCDCalcItems: + return fmt::format_to(ctx.out(), "BrtBeginPCDCalcItems"); + case xlsb_type::BrtEndPCDCalcItems: + return fmt::format_to(ctx.out(), "BrtEndPCDCalcItems"); + case xlsb_type::BrtBeginPCDCalcItem: + return fmt::format_to(ctx.out(), "BrtBeginPCDCalcItem"); + case xlsb_type::BrtEndPCDCalcItem: + return fmt::format_to(ctx.out(), "BrtEndPCDCalcItem"); + case xlsb_type::BrtBeginPRule: + return fmt::format_to(ctx.out(), "BrtBeginPRule"); + case xlsb_type::BrtEndPRule: + return fmt::format_to(ctx.out(), "BrtEndPRule"); + case xlsb_type::BrtBeginPRFilters: + return fmt::format_to(ctx.out(), "BrtBeginPRFilters"); + case xlsb_type::BrtEndPRFilters: + return fmt::format_to(ctx.out(), "BrtEndPRFilters"); + case xlsb_type::BrtBeginPRFilter: + return fmt::format_to(ctx.out(), "BrtBeginPRFilter"); + case xlsb_type::BrtEndPRFilter: + return fmt::format_to(ctx.out(), "BrtEndPRFilter"); + case xlsb_type::BrtBeginPNames: + return fmt::format_to(ctx.out(), "BrtBeginPNames"); + case xlsb_type::BrtEndPNames: + return fmt::format_to(ctx.out(), "BrtEndPNames"); + case xlsb_type::BrtBeginPName: + return fmt::format_to(ctx.out(), "BrtBeginPName"); + case xlsb_type::BrtEndPName: + return fmt::format_to(ctx.out(), "BrtEndPName"); + case xlsb_type::BrtBeginPNPairs: + return fmt::format_to(ctx.out(), "BrtBeginPNPairs"); + case xlsb_type::BrtEndPNPairs: + return fmt::format_to(ctx.out(), "BrtEndPNPairs"); + case xlsb_type::BrtBeginPNPair: + return fmt::format_to(ctx.out(), "BrtBeginPNPair"); + case xlsb_type::BrtEndPNPair: + return fmt::format_to(ctx.out(), "BrtEndPNPair"); + case xlsb_type::BrtBeginECWebProps: + return fmt::format_to(ctx.out(), "BrtBeginECWebProps"); + case xlsb_type::BrtEndECWebProps: + return fmt::format_to(ctx.out(), "BrtEndECWebProps"); + case xlsb_type::BrtBeginEcWpTables: + return fmt::format_to(ctx.out(), "BrtBeginEcWpTables"); + case xlsb_type::BrtEndECWPTables: + return fmt::format_to(ctx.out(), "BrtEndECWPTables"); + case xlsb_type::BrtBeginECParams: + return fmt::format_to(ctx.out(), "BrtBeginECParams"); + case xlsb_type::BrtEndECParams: + return fmt::format_to(ctx.out(), "BrtEndECParams"); + case xlsb_type::BrtBeginECParam: + return fmt::format_to(ctx.out(), "BrtBeginECParam"); + case xlsb_type::BrtEndECParam: + return fmt::format_to(ctx.out(), "BrtEndECParam"); + case xlsb_type::BrtBeginPCDKPIs: + return fmt::format_to(ctx.out(), "BrtBeginPCDKPIs"); + case xlsb_type::BrtEndPCDKPIs: + return fmt::format_to(ctx.out(), "BrtEndPCDKPIs"); + case xlsb_type::BrtBeginPCDKPI: + return fmt::format_to(ctx.out(), "BrtBeginPCDKPI"); + case xlsb_type::BrtEndPCDKPI: + return fmt::format_to(ctx.out(), "BrtEndPCDKPI"); + case xlsb_type::BrtBeginDims: + return fmt::format_to(ctx.out(), "BrtBeginDims"); + case xlsb_type::BrtEndDims: + return fmt::format_to(ctx.out(), "BrtEndDims"); + case xlsb_type::BrtBeginDim: + return fmt::format_to(ctx.out(), "BrtBeginDim"); + case xlsb_type::BrtEndDim: + return fmt::format_to(ctx.out(), "BrtEndDim"); + case xlsb_type::BrtIndexPartEnd: + return fmt::format_to(ctx.out(), "BrtIndexPartEnd"); + case xlsb_type::BrtBeginStyleSheet: + return fmt::format_to(ctx.out(), "BrtBeginStyleSheet"); + case xlsb_type::BrtEndStyleSheet: + return fmt::format_to(ctx.out(), "BrtEndStyleSheet"); + case xlsb_type::BrtBeginSXView: + return fmt::format_to(ctx.out(), "BrtBeginSXView"); + case xlsb_type::BrtEndSXVI: + return fmt::format_to(ctx.out(), "BrtEndSXVI"); + case xlsb_type::BrtBeginSXVI: + return fmt::format_to(ctx.out(), "BrtBeginSXVI"); + case xlsb_type::BrtBeginSXVIs: + return fmt::format_to(ctx.out(), "BrtBeginSXVIs"); + case xlsb_type::BrtEndSXVIs: + return fmt::format_to(ctx.out(), "BrtEndSXVIs"); + case xlsb_type::BrtBeginSXVD: + return fmt::format_to(ctx.out(), "BrtBeginSXVD"); + case xlsb_type::BrtEndSXVD: + return fmt::format_to(ctx.out(), "BrtEndSXVD"); + case xlsb_type::BrtBeginSXVDs: + return fmt::format_to(ctx.out(), "BrtBeginSXVDs"); + case xlsb_type::BrtEndSXVDs: + return fmt::format_to(ctx.out(), "BrtEndSXVDs"); + case xlsb_type::BrtBeginSXPI: + return fmt::format_to(ctx.out(), "BrtBeginSXPI"); + case xlsb_type::BrtEndSXPI: + return fmt::format_to(ctx.out(), "BrtEndSXPI"); + case xlsb_type::BrtBeginSXPIs: + return fmt::format_to(ctx.out(), "BrtBeginSXPIs"); + case xlsb_type::BrtEndSXPIs: + return fmt::format_to(ctx.out(), "BrtEndSXPIs"); + case xlsb_type::BrtBeginSXDI: + return fmt::format_to(ctx.out(), "BrtBeginSXDI"); + case xlsb_type::BrtEndSXDI: + return fmt::format_to(ctx.out(), "BrtEndSXDI"); + case xlsb_type::BrtBeginSXDIs: + return fmt::format_to(ctx.out(), "BrtBeginSXDIs"); + case xlsb_type::BrtEndSXDIs: + return fmt::format_to(ctx.out(), "BrtEndSXDIs"); + case xlsb_type::BrtBeginSXLI: + return fmt::format_to(ctx.out(), "BrtBeginSXLI"); + case xlsb_type::BrtEndSXLI: + return fmt::format_to(ctx.out(), "BrtEndSXLI"); + case xlsb_type::BrtBeginSXLIRws: + return fmt::format_to(ctx.out(), "BrtBeginSXLIRws"); + case xlsb_type::BrtEndSXLIRws: + return fmt::format_to(ctx.out(), "BrtEndSXLIRws"); + case xlsb_type::BrtBeginSXLICols: + return fmt::format_to(ctx.out(), "BrtBeginSXLICols"); + case xlsb_type::BrtEndSXLICols: + return fmt::format_to(ctx.out(), "BrtEndSXLICols"); + case xlsb_type::BrtBeginSXFormat: + return fmt::format_to(ctx.out(), "BrtBeginSXFormat"); + case xlsb_type::BrtEndSXFormat: + return fmt::format_to(ctx.out(), "BrtEndSXFormat"); + case xlsb_type::BrtBeginSXFormats: + return fmt::format_to(ctx.out(), "BrtBeginSXFormats"); + case xlsb_type::BrtEndSxFormats: + return fmt::format_to(ctx.out(), "BrtEndSxFormats"); + case xlsb_type::BrtBeginSxSelect: + return fmt::format_to(ctx.out(), "BrtBeginSxSelect"); + case xlsb_type::BrtEndSxSelect: + return fmt::format_to(ctx.out(), "BrtEndSxSelect"); + case xlsb_type::BrtBeginISXVDRws: + return fmt::format_to(ctx.out(), "BrtBeginISXVDRws"); + case xlsb_type::BrtEndISXVDRws: + return fmt::format_to(ctx.out(), "BrtEndISXVDRws"); + case xlsb_type::BrtBeginISXVDCols: + return fmt::format_to(ctx.out(), "BrtBeginISXVDCols"); + case xlsb_type::BrtEndISXVDCols: + return fmt::format_to(ctx.out(), "BrtEndISXVDCols"); + case xlsb_type::BrtEndSXLocation: + return fmt::format_to(ctx.out(), "BrtEndSXLocation"); + case xlsb_type::BrtBeginSXLocation: + return fmt::format_to(ctx.out(), "BrtBeginSXLocation"); + case xlsb_type::BrtEndSXView: + return fmt::format_to(ctx.out(), "BrtEndSXView"); + case xlsb_type::BrtBeginSXTHs: + return fmt::format_to(ctx.out(), "BrtBeginSXTHs"); + case xlsb_type::BrtEndSXTHs: + return fmt::format_to(ctx.out(), "BrtEndSXTHs"); + case xlsb_type::BrtBeginSXTH: + return fmt::format_to(ctx.out(), "BrtBeginSXTH"); + case xlsb_type::BrtEndSXTH: + return fmt::format_to(ctx.out(), "BrtEndSXTH"); + case xlsb_type::BrtBeginISXTHRws: + return fmt::format_to(ctx.out(), "BrtBeginISXTHRws"); + case xlsb_type::BrtEndISXTHRws: + return fmt::format_to(ctx.out(), "BrtEndISXTHRws"); + case xlsb_type::BrtBeginISXTHCols: + return fmt::format_to(ctx.out(), "BrtBeginISXTHCols"); + case xlsb_type::BrtEndISXTHCols: + return fmt::format_to(ctx.out(), "BrtEndISXTHCols"); + case xlsb_type::BrtBeginSXTDMPS: + return fmt::format_to(ctx.out(), "BrtBeginSXTDMPS"); + case xlsb_type::BrtEndSXTDMPs: + return fmt::format_to(ctx.out(), "BrtEndSXTDMPs"); + case xlsb_type::BrtBeginSXTDMP: + return fmt::format_to(ctx.out(), "BrtBeginSXTDMP"); + case xlsb_type::BrtEndSXTDMP: + return fmt::format_to(ctx.out(), "BrtEndSXTDMP"); + case xlsb_type::BrtBeginSXTHItems: + return fmt::format_to(ctx.out(), "BrtBeginSXTHItems"); + case xlsb_type::BrtEndSXTHItems: + return fmt::format_to(ctx.out(), "BrtEndSXTHItems"); + case xlsb_type::BrtBeginSXTHItem: + return fmt::format_to(ctx.out(), "BrtBeginSXTHItem"); + case xlsb_type::BrtEndSXTHItem: + return fmt::format_to(ctx.out(), "BrtEndSXTHItem"); + case xlsb_type::BrtBeginMetadata: + return fmt::format_to(ctx.out(), "BrtBeginMetadata"); + case xlsb_type::BrtEndMetadata: + return fmt::format_to(ctx.out(), "BrtEndMetadata"); + case xlsb_type::BrtBeginEsmdtinfo: + return fmt::format_to(ctx.out(), "BrtBeginEsmdtinfo"); + case xlsb_type::BrtMdtinfo: + return fmt::format_to(ctx.out(), "BrtMdtinfo"); + case xlsb_type::BrtEndEsmdtinfo: + return fmt::format_to(ctx.out(), "BrtEndEsmdtinfo"); + case xlsb_type::BrtBeginEsmdb: + return fmt::format_to(ctx.out(), "BrtBeginEsmdb"); + case xlsb_type::BrtEndEsmdb: + return fmt::format_to(ctx.out(), "BrtEndEsmdb"); + case xlsb_type::BrtBeginEsfmd: + return fmt::format_to(ctx.out(), "BrtBeginEsfmd"); + case xlsb_type::BrtEndEsfmd: + return fmt::format_to(ctx.out(), "BrtEndEsfmd"); + case xlsb_type::BrtBeginSingleCells: + return fmt::format_to(ctx.out(), "BrtBeginSingleCells"); + case xlsb_type::BrtEndSingleCells: + return fmt::format_to(ctx.out(), "BrtEndSingleCells"); + case xlsb_type::BrtBeginList: + return fmt::format_to(ctx.out(), "BrtBeginList"); + case xlsb_type::BrtEndList: + return fmt::format_to(ctx.out(), "BrtEndList"); + case xlsb_type::BrtBeginListCols: + return fmt::format_to(ctx.out(), "BrtBeginListCols"); + case xlsb_type::BrtEndListCols: + return fmt::format_to(ctx.out(), "BrtEndListCols"); + case xlsb_type::BrtBeginListCol: + return fmt::format_to(ctx.out(), "BrtBeginListCol"); + case xlsb_type::BrtEndListCol: + return fmt::format_to(ctx.out(), "BrtEndListCol"); + case xlsb_type::BrtBeginListXmlCPr: + return fmt::format_to(ctx.out(), "BrtBeginListXmlCPr"); + case xlsb_type::BrtEndListXmlCPr: + return fmt::format_to(ctx.out(), "BrtEndListXmlCPr"); + case xlsb_type::BrtListCCFmla: + return fmt::format_to(ctx.out(), "BrtListCCFmla"); + case xlsb_type::BrtListTrFmla: + return fmt::format_to(ctx.out(), "BrtListTrFmla"); + case xlsb_type::BrtBeginExternals: + return fmt::format_to(ctx.out(), "BrtBeginExternals"); + case xlsb_type::BrtEndExternals: + return fmt::format_to(ctx.out(), "BrtEndExternals"); + case xlsb_type::BrtSupBookSrc: + return fmt::format_to(ctx.out(), "BrtSupBookSrc"); + case xlsb_type::BrtSupSelf: + return fmt::format_to(ctx.out(), "BrtSupSelf"); + case xlsb_type::BrtSupSame: + return fmt::format_to(ctx.out(), "BrtSupSame"); + case xlsb_type::BrtSupTabs: + return fmt::format_to(ctx.out(), "BrtSupTabs"); + case xlsb_type::BrtBeginSupBook: + return fmt::format_to(ctx.out(), "BrtBeginSupBook"); + case xlsb_type::BrtPlaceholderName: + return fmt::format_to(ctx.out(), "BrtPlaceholderName"); + case xlsb_type::BrtExternSheet: + return fmt::format_to(ctx.out(), "BrtExternSheet"); + case xlsb_type::BrtExternTableStart: + return fmt::format_to(ctx.out(), "BrtExternTableStart"); + case xlsb_type::BrtExternTableEnd: + return fmt::format_to(ctx.out(), "BrtExternTableEnd"); + case xlsb_type::BrtExternRowHdr: + return fmt::format_to(ctx.out(), "BrtExternRowHdr"); + case xlsb_type::BrtExternCellBlank: + return fmt::format_to(ctx.out(), "BrtExternCellBlank"); + case xlsb_type::BrtExternCellReal: + return fmt::format_to(ctx.out(), "BrtExternCellReal"); + case xlsb_type::BrtExternCellBool: + return fmt::format_to(ctx.out(), "BrtExternCellBool"); + case xlsb_type::BrtExternCellError: + return fmt::format_to(ctx.out(), "BrtExternCellError"); + case xlsb_type::BrtExternCellString: + return fmt::format_to(ctx.out(), "BrtExternCellString"); + case xlsb_type::BrtBeginEsmdx: + return fmt::format_to(ctx.out(), "BrtBeginEsmdx"); + case xlsb_type::BrtEndEsmdx: + return fmt::format_to(ctx.out(), "BrtEndEsmdx"); + case xlsb_type::BrtBeginMdxSet: + return fmt::format_to(ctx.out(), "BrtBeginMdxSet"); + case xlsb_type::BrtEndMdxSet: + return fmt::format_to(ctx.out(), "BrtEndMdxSet"); + case xlsb_type::BrtBeginMdxMbrProp: + return fmt::format_to(ctx.out(), "BrtBeginMdxMbrProp"); + case xlsb_type::BrtEndMdxMbrProp: + return fmt::format_to(ctx.out(), "BrtEndMdxMbrProp"); + case xlsb_type::BrtBeginMdxKPI: + return fmt::format_to(ctx.out(), "BrtBeginMdxKPI"); + case xlsb_type::BrtEndMdxKPI: + return fmt::format_to(ctx.out(), "BrtEndMdxKPI"); + case xlsb_type::BrtBeginEsstr: + return fmt::format_to(ctx.out(), "BrtBeginEsstr"); + case xlsb_type::BrtEndEsstr: + return fmt::format_to(ctx.out(), "BrtEndEsstr"); + case xlsb_type::BrtBeginPRFItem: + return fmt::format_to(ctx.out(), "BrtBeginPRFItem"); + case xlsb_type::BrtEndPRFItem: + return fmt::format_to(ctx.out(), "BrtEndPRFItem"); + case xlsb_type::BrtBeginPivotCacheIDs: + return fmt::format_to(ctx.out(), "BrtBeginPivotCacheIDs"); + case xlsb_type::BrtEndPivotCacheIDs: + return fmt::format_to(ctx.out(), "BrtEndPivotCacheIDs"); + case xlsb_type::BrtBeginPivotCacheID: + return fmt::format_to(ctx.out(), "BrtBeginPivotCacheID"); + case xlsb_type::BrtEndPivotCacheID: + return fmt::format_to(ctx.out(), "BrtEndPivotCacheID"); + case xlsb_type::BrtBeginISXVIs: + return fmt::format_to(ctx.out(), "BrtBeginISXVIs"); + case xlsb_type::BrtEndISXVIs: + return fmt::format_to(ctx.out(), "BrtEndISXVIs"); + case xlsb_type::BrtBeginColInfos: + return fmt::format_to(ctx.out(), "BrtBeginColInfos"); + case xlsb_type::BrtEndColInfos: + return fmt::format_to(ctx.out(), "BrtEndColInfos"); + case xlsb_type::BrtBeginRwBrk: + return fmt::format_to(ctx.out(), "BrtBeginRwBrk"); + case xlsb_type::BrtEndRwBrk: + return fmt::format_to(ctx.out(), "BrtEndRwBrk"); + case xlsb_type::BrtBeginColBrk: + return fmt::format_to(ctx.out(), "BrtBeginColBrk"); + case xlsb_type::BrtEndColBrk: + return fmt::format_to(ctx.out(), "BrtEndColBrk"); + case xlsb_type::BrtBrk: + return fmt::format_to(ctx.out(), "BrtBrk"); + case xlsb_type::BrtUserBookView: + return fmt::format_to(ctx.out(), "BrtUserBookView"); + case xlsb_type::BrtInfo: + return fmt::format_to(ctx.out(), "BrtInfo"); + case xlsb_type::BrtCUsr: + return fmt::format_to(ctx.out(), "BrtCUsr"); + case xlsb_type::BrtUsr: + return fmt::format_to(ctx.out(), "BrtUsr"); + case xlsb_type::BrtBeginUsers: + return fmt::format_to(ctx.out(), "BrtBeginUsers"); + case xlsb_type::BrtEOF: + return fmt::format_to(ctx.out(), "BrtEOF"); + case xlsb_type::BrtUCR: + return fmt::format_to(ctx.out(), "BrtUCR"); + case xlsb_type::BrtRRInsDel: + return fmt::format_to(ctx.out(), "BrtRRInsDel"); + case xlsb_type::BrtRREndInsDel: + return fmt::format_to(ctx.out(), "BrtRREndInsDel"); + case xlsb_type::BrtRRMove: + return fmt::format_to(ctx.out(), "BrtRRMove"); + case xlsb_type::BrtRREndMove: + return fmt::format_to(ctx.out(), "BrtRREndMove"); + case xlsb_type::BrtRRChgCell: + return fmt::format_to(ctx.out(), "BrtRRChgCell"); + case xlsb_type::BrtRREndChgCell: + return fmt::format_to(ctx.out(), "BrtRREndChgCell"); + case xlsb_type::BrtRRHeader: + return fmt::format_to(ctx.out(), "BrtRRHeader"); + case xlsb_type::BrtRRUserView: + return fmt::format_to(ctx.out(), "BrtRRUserView"); + case xlsb_type::BrtRRRenSheet: + return fmt::format_to(ctx.out(), "BrtRRRenSheet"); + case xlsb_type::BrtRRInsertSh: + return fmt::format_to(ctx.out(), "BrtRRInsertSh"); + case xlsb_type::BrtRRDefName: + return fmt::format_to(ctx.out(), "BrtRRDefName"); + case xlsb_type::BrtRRNote: + return fmt::format_to(ctx.out(), "BrtRRNote"); + case xlsb_type::BrtRRConflict: + return fmt::format_to(ctx.out(), "BrtRRConflict"); + case xlsb_type::BrtRRTQSIF: + return fmt::format_to(ctx.out(), "BrtRRTQSIF"); + case xlsb_type::BrtRRFormat: + return fmt::format_to(ctx.out(), "BrtRRFormat"); + case xlsb_type::BrtRREndFormat: + return fmt::format_to(ctx.out(), "BrtRREndFormat"); + case xlsb_type::BrtRRAutoFmt: + return fmt::format_to(ctx.out(), "BrtRRAutoFmt"); + case xlsb_type::BrtBeginUserShViews: + return fmt::format_to(ctx.out(), "BrtBeginUserShViews"); + case xlsb_type::BrtBeginUserShView: + return fmt::format_to(ctx.out(), "BrtBeginUserShView"); + case xlsb_type::BrtEndUserShView: + return fmt::format_to(ctx.out(), "BrtEndUserShView"); + case xlsb_type::BrtEndUserShViews: + return fmt::format_to(ctx.out(), "BrtEndUserShViews"); + case xlsb_type::BrtArrFmla: + return fmt::format_to(ctx.out(), "BrtArrFmla"); + case xlsb_type::BrtShrFmla: + return fmt::format_to(ctx.out(), "BrtShrFmla"); + case xlsb_type::BrtTable: + return fmt::format_to(ctx.out(), "BrtTable"); + case xlsb_type::BrtBeginExtConnections: + return fmt::format_to(ctx.out(), "BrtBeginExtConnections"); + case xlsb_type::BrtEndExtConnections: + return fmt::format_to(ctx.out(), "BrtEndExtConnections"); + case xlsb_type::BrtBeginPCDCalcMems: + return fmt::format_to(ctx.out(), "BrtBeginPCDCalcMems"); + case xlsb_type::BrtEndPCDCalcMems: + return fmt::format_to(ctx.out(), "BrtEndPCDCalcMems"); + case xlsb_type::BrtBeginPCDCalcMem: + return fmt::format_to(ctx.out(), "BrtBeginPCDCalcMem"); + case xlsb_type::BrtEndPCDCalcMem: + return fmt::format_to(ctx.out(), "BrtEndPCDCalcMem"); + case xlsb_type::BrtBeginPCDHGLevels: + return fmt::format_to(ctx.out(), "BrtBeginPCDHGLevels"); + case xlsb_type::BrtEndPCDHGLevels: + return fmt::format_to(ctx.out(), "BrtEndPCDHGLevels"); + case xlsb_type::BrtBeginPCDHGLevel: + return fmt::format_to(ctx.out(), "BrtBeginPCDHGLevel"); + case xlsb_type::BrtEndPCDHGLevel: + return fmt::format_to(ctx.out(), "BrtEndPCDHGLevel"); + case xlsb_type::BrtBeginPCDHGLGroups: + return fmt::format_to(ctx.out(), "BrtBeginPCDHGLGroups"); + case xlsb_type::BrtEndPCDHGLGroups: + return fmt::format_to(ctx.out(), "BrtEndPCDHGLGroups"); + case xlsb_type::BrtBeginPCDHGLGroup: + return fmt::format_to(ctx.out(), "BrtBeginPCDHGLGroup"); + case xlsb_type::BrtEndPCDHGLGroup: + return fmt::format_to(ctx.out(), "BrtEndPCDHGLGroup"); + case xlsb_type::BrtBeginPCDHGLGMembers: + return fmt::format_to(ctx.out(), "BrtBeginPCDHGLGMembers"); + case xlsb_type::BrtEndPCDHGLGMembers: + return fmt::format_to(ctx.out(), "BrtEndPCDHGLGMembers"); + case xlsb_type::BrtBeginPCDHGLGMember: + return fmt::format_to(ctx.out(), "BrtBeginPCDHGLGMember"); + case xlsb_type::BrtEndPCDHGLGMember: + return fmt::format_to(ctx.out(), "BrtEndPCDHGLGMember"); + case xlsb_type::BrtBeginQSI: + return fmt::format_to(ctx.out(), "BrtBeginQSI"); + case xlsb_type::BrtEndQSI: + return fmt::format_to(ctx.out(), "BrtEndQSI"); + case xlsb_type::BrtBeginQSIR: + return fmt::format_to(ctx.out(), "BrtBeginQSIR"); + case xlsb_type::BrtEndQSIR: + return fmt::format_to(ctx.out(), "BrtEndQSIR"); + case xlsb_type::BrtBeginDeletedNames: + return fmt::format_to(ctx.out(), "BrtBeginDeletedNames"); + case xlsb_type::BrtEndDeletedNames: + return fmt::format_to(ctx.out(), "BrtEndDeletedNames"); + case xlsb_type::BrtBeginDeletedName: + return fmt::format_to(ctx.out(), "BrtBeginDeletedName"); + case xlsb_type::BrtEndDeletedName: + return fmt::format_to(ctx.out(), "BrtEndDeletedName"); + case xlsb_type::BrtBeginQSIFs: + return fmt::format_to(ctx.out(), "BrtBeginQSIFs"); + case xlsb_type::BrtEndQSIFs: + return fmt::format_to(ctx.out(), "BrtEndQSIFs"); + case xlsb_type::BrtBeginQSIF: + return fmt::format_to(ctx.out(), "BrtBeginQSIF"); + case xlsb_type::BrtEndQSIF: + return fmt::format_to(ctx.out(), "BrtEndQSIF"); + case xlsb_type::BrtBeginAutoSortScope: + return fmt::format_to(ctx.out(), "BrtBeginAutoSortScope"); + case xlsb_type::BrtEndAutoSortScope: + return fmt::format_to(ctx.out(), "BrtEndAutoSortScope"); + case xlsb_type::BrtBeginConditionalFormatting: + return fmt::format_to(ctx.out(), "BrtBeginConditionalFormatting"); + case xlsb_type::BrtEndConditionalFormatting: + return fmt::format_to(ctx.out(), "BrtEndConditionalFormatting"); + case xlsb_type::BrtBeginCFRule: + return fmt::format_to(ctx.out(), "BrtBeginCFRule"); + case xlsb_type::BrtEndCFRule: + return fmt::format_to(ctx.out(), "BrtEndCFRule"); + case xlsb_type::BrtBeginIconSet: + return fmt::format_to(ctx.out(), "BrtBeginIconSet"); + case xlsb_type::BrtEndIconSet: + return fmt::format_to(ctx.out(), "BrtEndIconSet"); + case xlsb_type::BrtBeginDatabar: + return fmt::format_to(ctx.out(), "BrtBeginDatabar"); + case xlsb_type::BrtEndDatabar: + return fmt::format_to(ctx.out(), "BrtEndDatabar"); + case xlsb_type::BrtBeginColorScale: + return fmt::format_to(ctx.out(), "BrtBeginColorScale"); + case xlsb_type::BrtEndColorScale: + return fmt::format_to(ctx.out(), "BrtEndColorScale"); + case xlsb_type::BrtCFVO: + return fmt::format_to(ctx.out(), "BrtCFVO"); + case xlsb_type::BrtExternValueMeta: + return fmt::format_to(ctx.out(), "BrtExternValueMeta"); + case xlsb_type::BrtBeginColorPalette: + return fmt::format_to(ctx.out(), "BrtBeginColorPalette"); + case xlsb_type::BrtEndColorPalette: + return fmt::format_to(ctx.out(), "BrtEndColorPalette"); + case xlsb_type::BrtIndexedColor: + return fmt::format_to(ctx.out(), "BrtIndexedColor"); + case xlsb_type::BrtMargins: + return fmt::format_to(ctx.out(), "BrtMargins"); + case xlsb_type::BrtPrintOptions: + return fmt::format_to(ctx.out(), "BrtPrintOptions"); + case xlsb_type::BrtPageSetup: + return fmt::format_to(ctx.out(), "BrtPageSetup"); + case xlsb_type::BrtBeginHeaderFooter: + return fmt::format_to(ctx.out(), "BrtBeginHeaderFooter"); + case xlsb_type::BrtEndHeaderFooter: + return fmt::format_to(ctx.out(), "BrtEndHeaderFooter"); + case xlsb_type::BrtBeginSXCrtFormat: + return fmt::format_to(ctx.out(), "BrtBeginSXCrtFormat"); + case xlsb_type::BrtEndSXCrtFormat: + return fmt::format_to(ctx.out(), "BrtEndSXCrtFormat"); + case xlsb_type::BrtBeginSXCrtFormats: + return fmt::format_to(ctx.out(), "BrtBeginSXCrtFormats"); + case xlsb_type::BrtEndSXCrtFormats: + return fmt::format_to(ctx.out(), "BrtEndSXCrtFormats"); + case xlsb_type::BrtWsFmtInfo: + return fmt::format_to(ctx.out(), "BrtWsFmtInfo"); + case xlsb_type::BrtBeginMgs: + return fmt::format_to(ctx.out(), "BrtBeginMgs"); + case xlsb_type::BrtEndMGs: + return fmt::format_to(ctx.out(), "BrtEndMGs"); + case xlsb_type::BrtBeginMGMaps: + return fmt::format_to(ctx.out(), "BrtBeginMGMaps"); + case xlsb_type::BrtEndMGMaps: + return fmt::format_to(ctx.out(), "BrtEndMGMaps"); + case xlsb_type::BrtBeginMG: + return fmt::format_to(ctx.out(), "BrtBeginMG"); + case xlsb_type::BrtEndMG: + return fmt::format_to(ctx.out(), "BrtEndMG"); + case xlsb_type::BrtBeginMap: + return fmt::format_to(ctx.out(), "BrtBeginMap"); + case xlsb_type::BrtEndMap: + return fmt::format_to(ctx.out(), "BrtEndMap"); + case xlsb_type::BrtHLink: + return fmt::format_to(ctx.out(), "BrtHLink"); + case xlsb_type::BrtBeginDCon: + return fmt::format_to(ctx.out(), "BrtBeginDCon"); + case xlsb_type::BrtEndDCon: + return fmt::format_to(ctx.out(), "BrtEndDCon"); + case xlsb_type::BrtBeginDRefs: + return fmt::format_to(ctx.out(), "BrtBeginDRefs"); + case xlsb_type::BrtEndDRefs: + return fmt::format_to(ctx.out(), "BrtEndDRefs"); + case xlsb_type::BrtDRef: + return fmt::format_to(ctx.out(), "BrtDRef"); + case xlsb_type::BrtBeginScenMan: + return fmt::format_to(ctx.out(), "BrtBeginScenMan"); + case xlsb_type::BrtEndScenMan: + return fmt::format_to(ctx.out(), "BrtEndScenMan"); + case xlsb_type::BrtBeginSct: + return fmt::format_to(ctx.out(), "BrtBeginSct"); + case xlsb_type::BrtEndSct: + return fmt::format_to(ctx.out(), "BrtEndSct"); + case xlsb_type::BrtSlc: + return fmt::format_to(ctx.out(), "BrtSlc"); + case xlsb_type::BrtBeginDXFs: + return fmt::format_to(ctx.out(), "BrtBeginDXFs"); + case xlsb_type::BrtEndDXFs: + return fmt::format_to(ctx.out(), "BrtEndDXFs"); + case xlsb_type::BrtDXF: + return fmt::format_to(ctx.out(), "BrtDXF"); + case xlsb_type::BrtBeginTableStyles: + return fmt::format_to(ctx.out(), "BrtBeginTableStyles"); + case xlsb_type::BrtEndTableStyles: + return fmt::format_to(ctx.out(), "BrtEndTableStyles"); + case xlsb_type::BrtBeginTableStyle: + return fmt::format_to(ctx.out(), "BrtBeginTableStyle"); + case xlsb_type::BrtEndTableStyle: + return fmt::format_to(ctx.out(), "BrtEndTableStyle"); + case xlsb_type::BrtTableStyleElement: + return fmt::format_to(ctx.out(), "BrtTableStyleElement"); + case xlsb_type::BrtTableStyleClient: + return fmt::format_to(ctx.out(), "BrtTableStyleClient"); + case xlsb_type::BrtBeginVolDeps: + return fmt::format_to(ctx.out(), "BrtBeginVolDeps"); + case xlsb_type::BrtEndVolDeps: + return fmt::format_to(ctx.out(), "BrtEndVolDeps"); + case xlsb_type::BrtBeginVolType: + return fmt::format_to(ctx.out(), "BrtBeginVolType"); + case xlsb_type::BrtEndVolType: + return fmt::format_to(ctx.out(), "BrtEndVolType"); + case xlsb_type::BrtBeginVolMain: + return fmt::format_to(ctx.out(), "BrtBeginVolMain"); + case xlsb_type::BrtEndVolMain: + return fmt::format_to(ctx.out(), "BrtEndVolMain"); + case xlsb_type::BrtBeginVolTopic: + return fmt::format_to(ctx.out(), "BrtBeginVolTopic"); + case xlsb_type::BrtEndVolTopic: + return fmt::format_to(ctx.out(), "BrtEndVolTopic"); + case xlsb_type::BrtVolSubtopic: + return fmt::format_to(ctx.out(), "BrtVolSubtopic"); + case xlsb_type::BrtVolRef: + return fmt::format_to(ctx.out(), "BrtVolRef"); + case xlsb_type::BrtVolNum: + return fmt::format_to(ctx.out(), "BrtVolNum"); + case xlsb_type::BrtVolErr: + return fmt::format_to(ctx.out(), "BrtVolErr"); + case xlsb_type::BrtVolStr: + return fmt::format_to(ctx.out(), "BrtVolStr"); + case xlsb_type::BrtVolBool: + return fmt::format_to(ctx.out(), "BrtVolBool"); + case xlsb_type::BrtBeginSortState: + return fmt::format_to(ctx.out(), "BrtBeginSortState"); + case xlsb_type::BrtEndSortState: + return fmt::format_to(ctx.out(), "BrtEndSortState"); + case xlsb_type::BrtBeginSortCond: + return fmt::format_to(ctx.out(), "BrtBeginSortCond"); + case xlsb_type::BrtEndSortCond: + return fmt::format_to(ctx.out(), "BrtEndSortCond"); + case xlsb_type::BrtBookProtection: + return fmt::format_to(ctx.out(), "BrtBookProtection"); + case xlsb_type::BrtSheetProtection: + return fmt::format_to(ctx.out(), "BrtSheetProtection"); + case xlsb_type::BrtRangeProtection: + return fmt::format_to(ctx.out(), "BrtRangeProtection"); + case xlsb_type::BrtPhoneticInfo: + return fmt::format_to(ctx.out(), "BrtPhoneticInfo"); + case xlsb_type::BrtBeginECTxtWiz: + return fmt::format_to(ctx.out(), "BrtBeginECTxtWiz"); + case xlsb_type::BrtEndECTxtWiz: + return fmt::format_to(ctx.out(), "BrtEndECTxtWiz"); + case xlsb_type::BrtBeginECTWFldInfoLst: + return fmt::format_to(ctx.out(), "BrtBeginECTWFldInfoLst"); + case xlsb_type::BrtEndECTWFldInfoLst: + return fmt::format_to(ctx.out(), "BrtEndECTWFldInfoLst"); + case xlsb_type::BrtBeginECTwFldInfo: + return fmt::format_to(ctx.out(), "BrtBeginECTwFldInfo"); + case xlsb_type::BrtFileSharing: + return fmt::format_to(ctx.out(), "BrtFileSharing"); + case xlsb_type::BrtOleSize: + return fmt::format_to(ctx.out(), "BrtOleSize"); + case xlsb_type::BrtDrawing: + return fmt::format_to(ctx.out(), "BrtDrawing"); + case xlsb_type::BrtLegacyDrawing: + return fmt::format_to(ctx.out(), "BrtLegacyDrawing"); + case xlsb_type::BrtLegacyDrawingHF: + return fmt::format_to(ctx.out(), "BrtLegacyDrawingHF"); + case xlsb_type::BrtWebOpt: + return fmt::format_to(ctx.out(), "BrtWebOpt"); + case xlsb_type::BrtBeginWebPubItems: + return fmt::format_to(ctx.out(), "BrtBeginWebPubItems"); + case xlsb_type::BrtEndWebPubItems: + return fmt::format_to(ctx.out(), "BrtEndWebPubItems"); + case xlsb_type::BrtBeginWebPubItem: + return fmt::format_to(ctx.out(), "BrtBeginWebPubItem"); + case xlsb_type::BrtEndWebPubItem: + return fmt::format_to(ctx.out(), "BrtEndWebPubItem"); + case xlsb_type::BrtBeginSXCondFmt: + return fmt::format_to(ctx.out(), "BrtBeginSXCondFmt"); + case xlsb_type::BrtEndSXCondFmt: + return fmt::format_to(ctx.out(), "BrtEndSXCondFmt"); + case xlsb_type::BrtBeginSXCondFmts: + return fmt::format_to(ctx.out(), "BrtBeginSXCondFmts"); + case xlsb_type::BrtEndSXCondFmts: + return fmt::format_to(ctx.out(), "BrtEndSXCondFmts"); + case xlsb_type::BrtBkHim: + return fmt::format_to(ctx.out(), "BrtBkHim"); + case xlsb_type::BrtColor: + return fmt::format_to(ctx.out(), "BrtColor"); + case xlsb_type::BrtBeginIndexedColors: + return fmt::format_to(ctx.out(), "BrtBeginIndexedColors"); + case xlsb_type::BrtEndIndexedColors: + return fmt::format_to(ctx.out(), "BrtEndIndexedColors"); + case xlsb_type::BrtBeginMRUColors: + return fmt::format_to(ctx.out(), "BrtBeginMRUColors"); + case xlsb_type::BrtEndMRUColors: + return fmt::format_to(ctx.out(), "BrtEndMRUColors"); + case xlsb_type::BrtMRUColor: + return fmt::format_to(ctx.out(), "BrtMRUColor"); + case xlsb_type::BrtBeginDVals: + return fmt::format_to(ctx.out(), "BrtBeginDVals"); + case xlsb_type::BrtEndDVals: + return fmt::format_to(ctx.out(), "BrtEndDVals"); + case xlsb_type::BrtSupNameStart: + return fmt::format_to(ctx.out(), "BrtSupNameStart"); + case xlsb_type::BrtSupNameValueStart: + return fmt::format_to(ctx.out(), "BrtSupNameValueStart"); + case xlsb_type::BrtSupNameValueEnd: + return fmt::format_to(ctx.out(), "BrtSupNameValueEnd"); + case xlsb_type::BrtSupNameNum: + return fmt::format_to(ctx.out(), "BrtSupNameNum"); + case xlsb_type::BrtSupNameErr: + return fmt::format_to(ctx.out(), "BrtSupNameErr"); + case xlsb_type::BrtSupNameSt: + return fmt::format_to(ctx.out(), "BrtSupNameSt"); + case xlsb_type::BrtSupNameNil: + return fmt::format_to(ctx.out(), "BrtSupNameNil"); + case xlsb_type::BrtSupNameBool: + return fmt::format_to(ctx.out(), "BrtSupNameBool"); + case xlsb_type::BrtSupNameFmla: + return fmt::format_to(ctx.out(), "BrtSupNameFmla"); + case xlsb_type::BrtSupNameBits: + return fmt::format_to(ctx.out(), "BrtSupNameBits"); + case xlsb_type::BrtSupNameEnd: + return fmt::format_to(ctx.out(), "BrtSupNameEnd"); + case xlsb_type::BrtEndSupBook: + return fmt::format_to(ctx.out(), "BrtEndSupBook"); + case xlsb_type::BrtCellSmartTagProperty: + return fmt::format_to(ctx.out(), "BrtCellSmartTagProperty"); + case xlsb_type::BrtBeginCellSmartTag: + return fmt::format_to(ctx.out(), "BrtBeginCellSmartTag"); + case xlsb_type::BrtEndCellSmartTag: + return fmt::format_to(ctx.out(), "BrtEndCellSmartTag"); + case xlsb_type::BrtBeginCellSmartTags: + return fmt::format_to(ctx.out(), "BrtBeginCellSmartTags"); + case xlsb_type::BrtEndCellSmartTags: + return fmt::format_to(ctx.out(), "BrtEndCellSmartTags"); + case xlsb_type::BrtBeginSmartTags: + return fmt::format_to(ctx.out(), "BrtBeginSmartTags"); + case xlsb_type::BrtEndSmartTags: + return fmt::format_to(ctx.out(), "BrtEndSmartTags"); + case xlsb_type::BrtSmartTagType: + return fmt::format_to(ctx.out(), "BrtSmartTagType"); + case xlsb_type::BrtBeginSmartTagTypes: + return fmt::format_to(ctx.out(), "BrtBeginSmartTagTypes"); + case xlsb_type::BrtEndSmartTagTypes: + return fmt::format_to(ctx.out(), "BrtEndSmartTagTypes"); + case xlsb_type::BrtBeginSXFilters: + return fmt::format_to(ctx.out(), "BrtBeginSXFilters"); + case xlsb_type::BrtEndSXFilters: + return fmt::format_to(ctx.out(), "BrtEndSXFilters"); + case xlsb_type::BrtBeginSXFILTER: + return fmt::format_to(ctx.out(), "BrtBeginSXFILTER"); + case xlsb_type::BrtEndSXFilter: + return fmt::format_to(ctx.out(), "BrtEndSXFilter"); + case xlsb_type::BrtBeginFills: + return fmt::format_to(ctx.out(), "BrtBeginFills"); + case xlsb_type::BrtEndFills: + return fmt::format_to(ctx.out(), "BrtEndFills"); + case xlsb_type::BrtBeginCellWatches: + return fmt::format_to(ctx.out(), "BrtBeginCellWatches"); + case xlsb_type::BrtEndCellWatches: + return fmt::format_to(ctx.out(), "BrtEndCellWatches"); + case xlsb_type::BrtCellWatch: + return fmt::format_to(ctx.out(), "BrtCellWatch"); + case xlsb_type::BrtBeginCRErrs: + return fmt::format_to(ctx.out(), "BrtBeginCRErrs"); + case xlsb_type::BrtEndCRErrs: + return fmt::format_to(ctx.out(), "BrtEndCRErrs"); + case xlsb_type::BrtCrashRecErr: + return fmt::format_to(ctx.out(), "BrtCrashRecErr"); + case xlsb_type::BrtBeginFonts: + return fmt::format_to(ctx.out(), "BrtBeginFonts"); + case xlsb_type::BrtEndFonts: + return fmt::format_to(ctx.out(), "BrtEndFonts"); + case xlsb_type::BrtBeginBorders: + return fmt::format_to(ctx.out(), "BrtBeginBorders"); + case xlsb_type::BrtEndBorders: + return fmt::format_to(ctx.out(), "BrtEndBorders"); + case xlsb_type::BrtBeginFmts: + return fmt::format_to(ctx.out(), "BrtBeginFmts"); + case xlsb_type::BrtEndFmts: + return fmt::format_to(ctx.out(), "BrtEndFmts"); + case xlsb_type::BrtBeginCellXFs: + return fmt::format_to(ctx.out(), "BrtBeginCellXFs"); + case xlsb_type::BrtEndCellXFs: + return fmt::format_to(ctx.out(), "BrtEndCellXFs"); + case xlsb_type::BrtBeginStyles: + return fmt::format_to(ctx.out(), "BrtBeginStyles"); + case xlsb_type::BrtEndStyles: + return fmt::format_to(ctx.out(), "BrtEndStyles"); + case xlsb_type::BrtBigName: + return fmt::format_to(ctx.out(), "BrtBigName"); + case xlsb_type::BrtBeginCellStyleXFs: + return fmt::format_to(ctx.out(), "BrtBeginCellStyleXFs"); + case xlsb_type::BrtEndCellStyleXFs: + return fmt::format_to(ctx.out(), "BrtEndCellStyleXFs"); + case xlsb_type::BrtBeginComments: + return fmt::format_to(ctx.out(), "BrtBeginComments"); + case xlsb_type::BrtEndComments: + return fmt::format_to(ctx.out(), "BrtEndComments"); + case xlsb_type::BrtBeginCommentAuthors: + return fmt::format_to(ctx.out(), "BrtBeginCommentAuthors"); + case xlsb_type::BrtEndCommentAuthors: + return fmt::format_to(ctx.out(), "BrtEndCommentAuthors"); + case xlsb_type::BrtCommentAuthor: + return fmt::format_to(ctx.out(), "BrtCommentAuthor"); + case xlsb_type::BrtBeginCommentList: + return fmt::format_to(ctx.out(), "BrtBeginCommentList"); + case xlsb_type::BrtEndCommentList: + return fmt::format_to(ctx.out(), "BrtEndCommentList"); + case xlsb_type::BrtBeginComment: + return fmt::format_to(ctx.out(), "BrtBeginComment"); + case xlsb_type::BrtEndComment: + return fmt::format_to(ctx.out(), "BrtEndComment"); + case xlsb_type::BrtCommentText: + return fmt::format_to(ctx.out(), "BrtCommentText"); + case xlsb_type::BrtBeginOleObjects: + return fmt::format_to(ctx.out(), "BrtBeginOleObjects"); + case xlsb_type::BrtOleObject: + return fmt::format_to(ctx.out(), "BrtOleObject"); + case xlsb_type::BrtEndOleObjects: + return fmt::format_to(ctx.out(), "BrtEndOleObjects"); + case xlsb_type::BrtBeginSxrules: + return fmt::format_to(ctx.out(), "BrtBeginSxrules"); + case xlsb_type::BrtEndSxRules: + return fmt::format_to(ctx.out(), "BrtEndSxRules"); + case xlsb_type::BrtBeginActiveXControls: + return fmt::format_to(ctx.out(), "BrtBeginActiveXControls"); + case xlsb_type::BrtActiveX: + return fmt::format_to(ctx.out(), "BrtActiveX"); + case xlsb_type::BrtEndActiveXControls: + return fmt::format_to(ctx.out(), "BrtEndActiveXControls"); + case xlsb_type::BrtBeginPCDSDTCEMembersSortBy: + return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCEMembersSortBy"); + case xlsb_type::BrtBeginCellIgnoreECs: + return fmt::format_to(ctx.out(), "BrtBeginCellIgnoreECs"); + case xlsb_type::BrtCellIgnoreEC: + return fmt::format_to(ctx.out(), "BrtCellIgnoreEC"); + case xlsb_type::BrtEndCellIgnoreECs: + return fmt::format_to(ctx.out(), "BrtEndCellIgnoreECs"); + case xlsb_type::BrtCsProp: + return fmt::format_to(ctx.out(), "BrtCsProp"); + case xlsb_type::BrtCsPageSetup: + return fmt::format_to(ctx.out(), "BrtCsPageSetup"); + case xlsb_type::BrtBeginUserCsViews: + return fmt::format_to(ctx.out(), "BrtBeginUserCsViews"); + case xlsb_type::BrtEndUserCsViews: + return fmt::format_to(ctx.out(), "BrtEndUserCsViews"); + case xlsb_type::BrtBeginUserCsView: + return fmt::format_to(ctx.out(), "BrtBeginUserCsView"); + case xlsb_type::BrtEndUserCsView: + return fmt::format_to(ctx.out(), "BrtEndUserCsView"); + case xlsb_type::BrtBeginPcdSFCIEntries: + return fmt::format_to(ctx.out(), "BrtBeginPcdSFCIEntries"); + case xlsb_type::BrtEndPCDSFCIEntries: + return fmt::format_to(ctx.out(), "BrtEndPCDSFCIEntries"); + case xlsb_type::BrtPCDSFCIEntry: + return fmt::format_to(ctx.out(), "BrtPCDSFCIEntry"); + case xlsb_type::BrtBeginListParts: + return fmt::format_to(ctx.out(), "BrtBeginListParts"); + case xlsb_type::BrtListPart: + return fmt::format_to(ctx.out(), "BrtListPart"); + case xlsb_type::BrtEndListParts: + return fmt::format_to(ctx.out(), "BrtEndListParts"); + case xlsb_type::BrtSheetCalcProp: + return fmt::format_to(ctx.out(), "BrtSheetCalcProp"); + case xlsb_type::BrtBeginFnGroup: + return fmt::format_to(ctx.out(), "BrtBeginFnGroup"); + case xlsb_type::BrtFnGroup: + return fmt::format_to(ctx.out(), "BrtFnGroup"); + case xlsb_type::BrtEndFnGroup: + return fmt::format_to(ctx.out(), "BrtEndFnGroup"); + case xlsb_type::BrtSupAddin: + return fmt::format_to(ctx.out(), "BrtSupAddin"); + case xlsb_type::BrtSXTDMPOrder: + return fmt::format_to(ctx.out(), "BrtSXTDMPOrder"); + case xlsb_type::BrtCsProtection: + return fmt::format_to(ctx.out(), "BrtCsProtection"); + case xlsb_type::BrtBeginWsSortMap: + return fmt::format_to(ctx.out(), "BrtBeginWsSortMap"); + case xlsb_type::BrtEndWsSortMap: + return fmt::format_to(ctx.out(), "BrtEndWsSortMap"); + case xlsb_type::BrtBeginRRSort: + return fmt::format_to(ctx.out(), "BrtBeginRRSort"); + case xlsb_type::BrtEndRRSort: + return fmt::format_to(ctx.out(), "BrtEndRRSort"); + case xlsb_type::BrtRRSortItem: + return fmt::format_to(ctx.out(), "BrtRRSortItem"); + case xlsb_type::BrtFileSharingIso: + return fmt::format_to(ctx.out(), "BrtFileSharingIso"); + case xlsb_type::BrtBookProtectionIso: + return fmt::format_to(ctx.out(), "BrtBookProtectionIso"); + case xlsb_type::BrtSheetProtectionIso: + return fmt::format_to(ctx.out(), "BrtSheetProtectionIso"); + case xlsb_type::BrtCsProtectionIso: + return fmt::format_to(ctx.out(), "BrtCsProtectionIso"); + case xlsb_type::BrtRangeProtectionIso: + return fmt::format_to(ctx.out(), "BrtRangeProtectionIso"); + case xlsb_type::BrtDValList: + return fmt::format_to(ctx.out(), "BrtDValList"); + case xlsb_type::BrtRwDescent: + return fmt::format_to(ctx.out(), "BrtRwDescent"); + case xlsb_type::BrtKnownFonts: + return fmt::format_to(ctx.out(), "BrtKnownFonts"); + case xlsb_type::BrtBeginSXTupleSet: + return fmt::format_to(ctx.out(), "BrtBeginSXTupleSet"); + case xlsb_type::BrtEndSXTupleSet: + return fmt::format_to(ctx.out(), "BrtEndSXTupleSet"); + case xlsb_type::BrtBeginSXTupleSetHeader: + return fmt::format_to(ctx.out(), "BrtBeginSXTupleSetHeader"); + case xlsb_type::BrtEndSXTupleSetHeader: + return fmt::format_to(ctx.out(), "BrtEndSXTupleSetHeader"); + case xlsb_type::BrtSXTupleSetHeaderItem: + return fmt::format_to(ctx.out(), "BrtSXTupleSetHeaderItem"); + case xlsb_type::BrtBeginSXTupleSetData: + return fmt::format_to(ctx.out(), "BrtBeginSXTupleSetData"); + case xlsb_type::BrtEndSXTupleSetData: + return fmt::format_to(ctx.out(), "BrtEndSXTupleSetData"); + case xlsb_type::BrtBeginSXTupleSetRow: + return fmt::format_to(ctx.out(), "BrtBeginSXTupleSetRow"); + case xlsb_type::BrtEndSXTupleSetRow: + return fmt::format_to(ctx.out(), "BrtEndSXTupleSetRow"); + case xlsb_type::BrtSXTupleSetRowItem: + return fmt::format_to(ctx.out(), "BrtSXTupleSetRowItem"); + case xlsb_type::BrtNameExt: + return fmt::format_to(ctx.out(), "BrtNameExt"); + case xlsb_type::BrtPCDH14: + return fmt::format_to(ctx.out(), "BrtPCDH14"); + case xlsb_type::BrtBeginPCDCalcMem14: + return fmt::format_to(ctx.out(), "BrtBeginPCDCalcMem14"); + case xlsb_type::BrtEndPCDCalcMem14: + return fmt::format_to(ctx.out(), "BrtEndPCDCalcMem14"); + case xlsb_type::BrtSXTH14: + return fmt::format_to(ctx.out(), "BrtSXTH14"); + case xlsb_type::BrtBeginSparklineGroup: + return fmt::format_to(ctx.out(), "BrtBeginSparklineGroup"); + case xlsb_type::BrtEndSparklineGroup: + return fmt::format_to(ctx.out(), "BrtEndSparklineGroup"); + case xlsb_type::BrtSparkline: + return fmt::format_to(ctx.out(), "BrtSparkline"); + case xlsb_type::BrtSXDI14: + return fmt::format_to(ctx.out(), "BrtSXDI14"); + case xlsb_type::BrtWsFmtInfoEx14: + return fmt::format_to(ctx.out(), "BrtWsFmtInfoEx14"); + case xlsb_type::BrtBeginConditionalFormatting14: + return fmt::format_to(ctx.out(), "BrtBeginConditionalFormatting14"); + case xlsb_type::BrtEndConditionalFormatting14: + return fmt::format_to(ctx.out(), "BrtEndConditionalFormatting14"); + case xlsb_type::BrtBeginCFRule14: + return fmt::format_to(ctx.out(), "BrtBeginCFRule14"); + case xlsb_type::BrtEndCFRule14: + return fmt::format_to(ctx.out(), "BrtEndCFRule14"); + case xlsb_type::BrtCFVO14: + return fmt::format_to(ctx.out(), "BrtCFVO14"); + case xlsb_type::BrtBeginDatabar14: + return fmt::format_to(ctx.out(), "BrtBeginDatabar14"); + case xlsb_type::BrtBeginIconSet14: + return fmt::format_to(ctx.out(), "BrtBeginIconSet14"); + case xlsb_type::BrtDVal14: + return fmt::format_to(ctx.out(), "BrtDVal14"); + case xlsb_type::BrtBeginDVals14: + return fmt::format_to(ctx.out(), "BrtBeginDVals14"); + case xlsb_type::BrtColor14: + return fmt::format_to(ctx.out(), "BrtColor14"); + case xlsb_type::BrtBeginSparklines: + return fmt::format_to(ctx.out(), "BrtBeginSparklines"); + case xlsb_type::BrtEndSparklines: + return fmt::format_to(ctx.out(), "BrtEndSparklines"); + case xlsb_type::BrtBeginSparklineGroups: + return fmt::format_to(ctx.out(), "BrtBeginSparklineGroups"); + case xlsb_type::BrtEndSparklineGroups: + return fmt::format_to(ctx.out(), "BrtEndSparklineGroups"); + case xlsb_type::BrtSXVD14: + return fmt::format_to(ctx.out(), "BrtSXVD14"); + case xlsb_type::BrtBeginSxView14: + return fmt::format_to(ctx.out(), "BrtBeginSxView14"); + case xlsb_type::BrtEndSxView14: + return fmt::format_to(ctx.out(), "BrtEndSxView14"); + case xlsb_type::BrtBeginSXView16: + return fmt::format_to(ctx.out(), "BrtBeginSXView16"); + case xlsb_type::BrtEndSXView16: + return fmt::format_to(ctx.out(), "BrtEndSXView16"); + case xlsb_type::BrtBeginPCD14: + return fmt::format_to(ctx.out(), "BrtBeginPCD14"); + case xlsb_type::BrtEndPCD14: + return fmt::format_to(ctx.out(), "BrtEndPCD14"); + case xlsb_type::BrtBeginExtConn14: + return fmt::format_to(ctx.out(), "BrtBeginExtConn14"); + case xlsb_type::BrtEndExtConn14: + return fmt::format_to(ctx.out(), "BrtEndExtConn14"); + case xlsb_type::BrtBeginSlicerCacheIDs: + return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheIDs"); + case xlsb_type::BrtEndSlicerCacheIDs: + return fmt::format_to(ctx.out(), "BrtEndSlicerCacheIDs"); + case xlsb_type::BrtBeginSlicerCacheID: + return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheID"); + case xlsb_type::BrtEndSlicerCacheID: + return fmt::format_to(ctx.out(), "BrtEndSlicerCacheID"); + case xlsb_type::BrtBeginSlicerCache: + return fmt::format_to(ctx.out(), "BrtBeginSlicerCache"); + case xlsb_type::BrtEndSlicerCache: + return fmt::format_to(ctx.out(), "BrtEndSlicerCache"); + case xlsb_type::BrtBeginSlicerCacheDef: + return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheDef"); + case xlsb_type::BrtEndSlicerCacheDef: + return fmt::format_to(ctx.out(), "BrtEndSlicerCacheDef"); + case xlsb_type::BrtBeginSlicersEx: + return fmt::format_to(ctx.out(), "BrtBeginSlicersEx"); + case xlsb_type::BrtEndSlicersEx: + return fmt::format_to(ctx.out(), "BrtEndSlicersEx"); + case xlsb_type::BrtBeginSlicerEx: + return fmt::format_to(ctx.out(), "BrtBeginSlicerEx"); + case xlsb_type::BrtEndSlicerEx: + return fmt::format_to(ctx.out(), "BrtEndSlicerEx"); + case xlsb_type::BrtBeginSlicer: + return fmt::format_to(ctx.out(), "BrtBeginSlicer"); + case xlsb_type::BrtEndSlicer: + return fmt::format_to(ctx.out(), "BrtEndSlicer"); + case xlsb_type::BrtSlicerCachePivotTables: + return fmt::format_to(ctx.out(), "BrtSlicerCachePivotTables"); + case xlsb_type::BrtBeginSlicerCacheOlapImpl: + return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheOlapImpl"); + case xlsb_type::BrtEndSlicerCacheOlapImpl: + return fmt::format_to(ctx.out(), "BrtEndSlicerCacheOlapImpl"); + case xlsb_type::BrtBeginSlicerCacheLevelsData: + return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheLevelsData"); + case xlsb_type::BrtEndSlicerCacheLevelsData: + return fmt::format_to(ctx.out(), "BrtEndSlicerCacheLevelsData"); + case xlsb_type::BrtBeginSlicerCacheLevelData: + return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheLevelData"); + case xlsb_type::BrtEndSlicerCacheLevelData: + return fmt::format_to(ctx.out(), "BrtEndSlicerCacheLevelData"); + case xlsb_type::BrtBeginSlicerCacheSiRanges: + return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheSiRanges"); + case xlsb_type::BrtEndSlicerCacheSiRanges: + return fmt::format_to(ctx.out(), "BrtEndSlicerCacheSiRanges"); + case xlsb_type::BrtBeginSlicerCacheSiRange: + return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheSiRange"); + case xlsb_type::BrtEndSlicerCacheSiRange: + return fmt::format_to(ctx.out(), "BrtEndSlicerCacheSiRange"); + case xlsb_type::BrtSlicerCacheOlapItem: + return fmt::format_to(ctx.out(), "BrtSlicerCacheOlapItem"); + case xlsb_type::BrtBeginSlicerCacheSelections: + return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheSelections"); + case xlsb_type::BrtSlicerCacheSelection: + return fmt::format_to(ctx.out(), "BrtSlicerCacheSelection"); + case xlsb_type::BrtEndSlicerCacheSelections: + return fmt::format_to(ctx.out(), "BrtEndSlicerCacheSelections"); + case xlsb_type::BrtBeginSlicerCacheNative: + return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheNative"); + case xlsb_type::BrtEndSlicerCacheNative: + return fmt::format_to(ctx.out(), "BrtEndSlicerCacheNative"); + case xlsb_type::BrtSlicerCacheNativeItem: + return fmt::format_to(ctx.out(), "BrtSlicerCacheNativeItem"); + case xlsb_type::BrtRangeProtection14: + return fmt::format_to(ctx.out(), "BrtRangeProtection14"); + case xlsb_type::BrtRangeProtectionIso14: + return fmt::format_to(ctx.out(), "BrtRangeProtectionIso14"); + case xlsb_type::BrtCellIgnoreEC14: + return fmt::format_to(ctx.out(), "BrtCellIgnoreEC14"); + case xlsb_type::BrtList14: + return fmt::format_to(ctx.out(), "BrtList14"); + case xlsb_type::BrtCFIcon: + return fmt::format_to(ctx.out(), "BrtCFIcon"); + case xlsb_type::BrtBeginSlicerCachesPivotCacheIDs: + return fmt::format_to(ctx.out(), "BrtBeginSlicerCachesPivotCacheIDs"); + case xlsb_type::BrtEndSlicerCachesPivotCacheIDs: + return fmt::format_to(ctx.out(), "BrtEndSlicerCachesPivotCacheIDs"); + case xlsb_type::BrtBeginSlicers: + return fmt::format_to(ctx.out(), "BrtBeginSlicers"); + case xlsb_type::BrtEndSlicers: + return fmt::format_to(ctx.out(), "BrtEndSlicers"); + case xlsb_type::BrtWbProp14: + return fmt::format_to(ctx.out(), "BrtWbProp14"); + case xlsb_type::BrtBeginSXEdit: + return fmt::format_to(ctx.out(), "BrtBeginSXEdit"); + case xlsb_type::BrtEndSXEdit: + return fmt::format_to(ctx.out(), "BrtEndSXEdit"); + case xlsb_type::BrtBeginSXEdits: + return fmt::format_to(ctx.out(), "BrtBeginSXEdits"); + case xlsb_type::BrtEndSXEdits: + return fmt::format_to(ctx.out(), "BrtEndSXEdits"); + case xlsb_type::BrtBeginSXChange: + return fmt::format_to(ctx.out(), "BrtBeginSXChange"); + case xlsb_type::BrtEndSXChange: + return fmt::format_to(ctx.out(), "BrtEndSXChange"); + case xlsb_type::BrtBeginSXChanges: + return fmt::format_to(ctx.out(), "BrtBeginSXChanges"); + case xlsb_type::BrtEndSXChanges: + return fmt::format_to(ctx.out(), "BrtEndSXChanges"); + case xlsb_type::BrtSXTupleItems: + return fmt::format_to(ctx.out(), "BrtSXTupleItems"); + case xlsb_type::BrtBeginSlicerStyle: + return fmt::format_to(ctx.out(), "BrtBeginSlicerStyle"); + case xlsb_type::BrtEndSlicerStyle: + return fmt::format_to(ctx.out(), "BrtEndSlicerStyle"); + case xlsb_type::BrtSlicerStyleElement: + return fmt::format_to(ctx.out(), "BrtSlicerStyleElement"); + case xlsb_type::BrtBeginStyleSheetExt14: + return fmt::format_to(ctx.out(), "BrtBeginStyleSheetExt14"); + case xlsb_type::BrtEndStyleSheetExt14: + return fmt::format_to(ctx.out(), "BrtEndStyleSheetExt14"); + case xlsb_type::BrtBeginSlicerCachesPivotCacheID: + return fmt::format_to(ctx.out(), "BrtBeginSlicerCachesPivotCacheID"); + case xlsb_type::BrtEndSlicerCachesPivotCacheID: + return fmt::format_to(ctx.out(), "BrtEndSlicerCachesPivotCacheID"); + case xlsb_type::BrtBeginConditionalFormattings: + return fmt::format_to(ctx.out(), "BrtBeginConditionalFormattings"); + case xlsb_type::BrtEndConditionalFormattings: + return fmt::format_to(ctx.out(), "BrtEndConditionalFormattings"); + case xlsb_type::BrtBeginPCDCalcMemExt: + return fmt::format_to(ctx.out(), "BrtBeginPCDCalcMemExt"); + case xlsb_type::BrtEndPCDCalcMemExt: + return fmt::format_to(ctx.out(), "BrtEndPCDCalcMemExt"); + case xlsb_type::BrtBeginPCDCalcMemsExt: + return fmt::format_to(ctx.out(), "BrtBeginPCDCalcMemsExt"); + case xlsb_type::BrtEndPCDCalcMemsExt: + return fmt::format_to(ctx.out(), "BrtEndPCDCalcMemsExt"); + case xlsb_type::BrtPCDField14: + return fmt::format_to(ctx.out(), "BrtPCDField14"); + case xlsb_type::BrtBeginSlicerStyles: + return fmt::format_to(ctx.out(), "BrtBeginSlicerStyles"); + case xlsb_type::BrtEndSlicerStyles: + return fmt::format_to(ctx.out(), "BrtEndSlicerStyles"); + case xlsb_type::BrtBeginSlicerStyleElements: + return fmt::format_to(ctx.out(), "BrtBeginSlicerStyleElements"); + case xlsb_type::BrtEndSlicerStyleElements: + return fmt::format_to(ctx.out(), "BrtEndSlicerStyleElements"); + case xlsb_type::BrtCFRuleExt: + return fmt::format_to(ctx.out(), "BrtCFRuleExt"); + case xlsb_type::BrtBeginSXCondFmt14: + return fmt::format_to(ctx.out(), "BrtBeginSXCondFmt14"); + case xlsb_type::BrtEndSXCondFmt14: + return fmt::format_to(ctx.out(), "BrtEndSXCondFmt14"); + case xlsb_type::BrtBeginSXCondFmts14: + return fmt::format_to(ctx.out(), "BrtBeginSXCondFmts14"); + case xlsb_type::BrtEndSXCondFmts14: + return fmt::format_to(ctx.out(), "BrtEndSXCondFmts14"); + case xlsb_type::BrtBeginSortCond14: + return fmt::format_to(ctx.out(), "BrtBeginSortCond14"); + case xlsb_type::BrtEndSortCond14: + return fmt::format_to(ctx.out(), "BrtEndSortCond14"); + case xlsb_type::BrtEndDVals14: + return fmt::format_to(ctx.out(), "BrtEndDVals14"); + case xlsb_type::BrtEndIconSet14: + return fmt::format_to(ctx.out(), "BrtEndIconSet14"); + case xlsb_type::BrtEndDatabar14: + return fmt::format_to(ctx.out(), "BrtEndDatabar14"); + case xlsb_type::BrtBeginColorScale14: + return fmt::format_to(ctx.out(), "BrtBeginColorScale14"); + case xlsb_type::BrtEndColorScale14: + return fmt::format_to(ctx.out(), "BrtEndColorScale14"); + case xlsb_type::BrtBeginSxrules14: + return fmt::format_to(ctx.out(), "BrtBeginSxrules14"); + case xlsb_type::BrtEndSxrules14: + return fmt::format_to(ctx.out(), "BrtEndSxrules14"); + case xlsb_type::BrtBeginPRule14: + return fmt::format_to(ctx.out(), "BrtBeginPRule14"); + case xlsb_type::BrtEndPRule14: + return fmt::format_to(ctx.out(), "BrtEndPRule14"); + case xlsb_type::BrtBeginPRFilters14: + return fmt::format_to(ctx.out(), "BrtBeginPRFilters14"); + case xlsb_type::BrtEndPRFilters14: + return fmt::format_to(ctx.out(), "BrtEndPRFilters14"); + case xlsb_type::BrtBeginPRFilter14: + return fmt::format_to(ctx.out(), "BrtBeginPRFilter14"); + case xlsb_type::BrtEndPRFilter14: + return fmt::format_to(ctx.out(), "BrtEndPRFilter14"); + case xlsb_type::BrtBeginPRFItem14: + return fmt::format_to(ctx.out(), "BrtBeginPRFItem14"); + case xlsb_type::BrtEndPRFItem14: + return fmt::format_to(ctx.out(), "BrtEndPRFItem14"); + case xlsb_type::BrtBeginCellIgnoreECs14: + return fmt::format_to(ctx.out(), "BrtBeginCellIgnoreECs14"); + case xlsb_type::BrtEndCellIgnoreECs14: + return fmt::format_to(ctx.out(), "BrtEndCellIgnoreECs14"); + case xlsb_type::BrtDxf14: + return fmt::format_to(ctx.out(), "BrtDxf14"); + case xlsb_type::BrtBeginDxF14s: + return fmt::format_to(ctx.out(), "BrtBeginDxF14s"); + case xlsb_type::BrtEndDxf14s: + return fmt::format_to(ctx.out(), "BrtEndDxf14s"); + case xlsb_type::BrtFilter14: + return fmt::format_to(ctx.out(), "BrtFilter14"); + case xlsb_type::BrtBeginCustomFilters14: + return fmt::format_to(ctx.out(), "BrtBeginCustomFilters14"); + case xlsb_type::BrtCustomFilter14: + return fmt::format_to(ctx.out(), "BrtCustomFilter14"); + case xlsb_type::BrtIconFilter14: + return fmt::format_to(ctx.out(), "BrtIconFilter14"); + case xlsb_type::BrtPivotCacheConnectionName: + return fmt::format_to(ctx.out(), "BrtPivotCacheConnectionName"); + case xlsb_type::BrtBeginDecoupledPivotCacheIDs: + return fmt::format_to(ctx.out(), "BrtBeginDecoupledPivotCacheIDs"); + case xlsb_type::BrtEndDecoupledPivotCacheIDs: + return fmt::format_to(ctx.out(), "BrtEndDecoupledPivotCacheIDs"); + case xlsb_type::BrtDecoupledPivotCacheID: + return fmt::format_to(ctx.out(), "BrtDecoupledPivotCacheID"); + case xlsb_type::BrtBeginPivotTableRefs: + return fmt::format_to(ctx.out(), "BrtBeginPivotTableRefs"); + case xlsb_type::BrtEndPivotTableRefs: + return fmt::format_to(ctx.out(), "BrtEndPivotTableRefs"); + case xlsb_type::BrtPivotTableRef: + return fmt::format_to(ctx.out(), "BrtPivotTableRef"); + case xlsb_type::BrtSlicerCacheBookPivotTables: + return fmt::format_to(ctx.out(), "BrtSlicerCacheBookPivotTables"); + case xlsb_type::BrtBeginSxvcells: + return fmt::format_to(ctx.out(), "BrtBeginSxvcells"); + case xlsb_type::BrtEndSxvcells: + return fmt::format_to(ctx.out(), "BrtEndSxvcells"); + case xlsb_type::BrtBeginSxRow: + return fmt::format_to(ctx.out(), "BrtBeginSxRow"); + case xlsb_type::BrtEndSxRow: + return fmt::format_to(ctx.out(), "BrtEndSxRow"); + case xlsb_type::BrtPcdCalcMem15: + return fmt::format_to(ctx.out(), "BrtPcdCalcMem15"); + case xlsb_type::BrtQsi15: + return fmt::format_to(ctx.out(), "BrtQsi15"); + case xlsb_type::BrtBeginWebExtensions: + return fmt::format_to(ctx.out(), "BrtBeginWebExtensions"); + case xlsb_type::BrtEndWebExtensions: + return fmt::format_to(ctx.out(), "BrtEndWebExtensions"); + case xlsb_type::BrtWebExtension: + return fmt::format_to(ctx.out(), "BrtWebExtension"); + case xlsb_type::BrtAbsPath15: + return fmt::format_to(ctx.out(), "BrtAbsPath15"); + case xlsb_type::BrtBeginPivotTableUISettings: + return fmt::format_to(ctx.out(), "BrtBeginPivotTableUISettings"); + case xlsb_type::BrtEndPivotTableUISettings: + return fmt::format_to(ctx.out(), "BrtEndPivotTableUISettings"); + case xlsb_type::BrtTableSlicerCacheIDs: + return fmt::format_to(ctx.out(), "BrtTableSlicerCacheIDs"); + case xlsb_type::BrtTableSlicerCacheID: + return fmt::format_to(ctx.out(), "BrtTableSlicerCacheID"); + case xlsb_type::BrtBeginTableSlicerCache: + return fmt::format_to(ctx.out(), "BrtBeginTableSlicerCache"); + case xlsb_type::BrtEndTableSlicerCache: + return fmt::format_to(ctx.out(), "BrtEndTableSlicerCache"); + case xlsb_type::BrtSxFilter15: + return fmt::format_to(ctx.out(), "BrtSxFilter15"); + case xlsb_type::BrtBeginTimelineCachePivotCacheIDs: + return fmt::format_to(ctx.out(), "BrtBeginTimelineCachePivotCacheIDs"); + case xlsb_type::BrtEndTimelineCachePivotCacheIDs: + return fmt::format_to(ctx.out(), "BrtEndTimelineCachePivotCacheIDs"); + case xlsb_type::BrtTimelineCachePivotCacheID: + return fmt::format_to(ctx.out(), "BrtTimelineCachePivotCacheID"); + case xlsb_type::BrtBeginTimelineCacheIDs: + return fmt::format_to(ctx.out(), "BrtBeginTimelineCacheIDs"); + case xlsb_type::BrtEndTimelineCacheIDs: + return fmt::format_to(ctx.out(), "BrtEndTimelineCacheIDs"); + case xlsb_type::BrtBeginTimelineCacheID: + return fmt::format_to(ctx.out(), "BrtBeginTimelineCacheID"); + case xlsb_type::BrtEndTimelineCacheID: + return fmt::format_to(ctx.out(), "BrtEndTimelineCacheID"); + case xlsb_type::BrtBeginTimelinesEx: + return fmt::format_to(ctx.out(), "BrtBeginTimelinesEx"); + case xlsb_type::BrtEndTimelinesEx: + return fmt::format_to(ctx.out(), "BrtEndTimelinesEx"); + case xlsb_type::BrtBeginTimelineEx: + return fmt::format_to(ctx.out(), "BrtBeginTimelineEx"); + case xlsb_type::BrtEndTimelineEx: + return fmt::format_to(ctx.out(), "BrtEndTimelineEx"); + case xlsb_type::BrtWorkBookPr15: + return fmt::format_to(ctx.out(), "BrtWorkBookPr15"); + case xlsb_type::BrtPCDH15: + return fmt::format_to(ctx.out(), "BrtPCDH15"); + case xlsb_type::BrtBeginTimelineStyle: + return fmt::format_to(ctx.out(), "BrtBeginTimelineStyle"); + case xlsb_type::BrtEndTimelineStyle: + return fmt::format_to(ctx.out(), "BrtEndTimelineStyle"); + case xlsb_type::BrtTimelineStyleElement: + return fmt::format_to(ctx.out(), "BrtTimelineStyleElement"); + case xlsb_type::BrtBeginTimelineStylesheetExt15: + return fmt::format_to(ctx.out(), "BrtBeginTimelineStylesheetExt15"); + case xlsb_type::BrtEndTimelineStylesheetExt15: + return fmt::format_to(ctx.out(), "BrtEndTimelineStylesheetExt15"); + case xlsb_type::BrtBeginTimelineStyles: + return fmt::format_to(ctx.out(), "BrtBeginTimelineStyles"); + case xlsb_type::BrtEndTimelineStyles: + return fmt::format_to(ctx.out(), "BrtEndTimelineStyles"); + case xlsb_type::BrtBeginTimelineStyleElements: + return fmt::format_to(ctx.out(), "BrtBeginTimelineStyleElements"); + case xlsb_type::BrtEndTimelineStyleElements: + return fmt::format_to(ctx.out(), "BrtEndTimelineStyleElements"); + case xlsb_type::BrtDxf15: + return fmt::format_to(ctx.out(), "BrtDxf15"); + case xlsb_type::BrtBeginDxfs15: + return fmt::format_to(ctx.out(), "BrtBeginDxfs15"); + case xlsb_type::BrtEndDXFs15: + return fmt::format_to(ctx.out(), "BrtEndDXFs15"); + case xlsb_type::BrtSlicerCacheHideItemsWithNoData: + return fmt::format_to(ctx.out(), "BrtSlicerCacheHideItemsWithNoData"); + case xlsb_type::BrtBeginItemUniqueNames: + return fmt::format_to(ctx.out(), "BrtBeginItemUniqueNames"); + case xlsb_type::BrtEndItemUniqueNames: + return fmt::format_to(ctx.out(), "BrtEndItemUniqueNames"); + case xlsb_type::BrtItemUniqueName: + return fmt::format_to(ctx.out(), "BrtItemUniqueName"); + case xlsb_type::BrtBeginExtConn15: + return fmt::format_to(ctx.out(), "BrtBeginExtConn15"); + case xlsb_type::BrtEndExtConn15: + return fmt::format_to(ctx.out(), "BrtEndExtConn15"); + case xlsb_type::BrtBeginOledbPr15: + return fmt::format_to(ctx.out(), "BrtBeginOledbPr15"); + case xlsb_type::BrtEndOledbPr15: + return fmt::format_to(ctx.out(), "BrtEndOledbPr15"); + case xlsb_type::BrtBeginDataFeedPr15: + return fmt::format_to(ctx.out(), "BrtBeginDataFeedPr15"); + case xlsb_type::BrtEndDataFeedPr15: + return fmt::format_to(ctx.out(), "BrtEndDataFeedPr15"); + case xlsb_type::BrtTextPr15: + return fmt::format_to(ctx.out(), "BrtTextPr15"); + case xlsb_type::BrtRangePr15: + return fmt::format_to(ctx.out(), "BrtRangePr15"); + case xlsb_type::BrtDbCommand15: + return fmt::format_to(ctx.out(), "BrtDbCommand15"); + case xlsb_type::BrtBeginDbTables15: + return fmt::format_to(ctx.out(), "BrtBeginDbTables15"); + case xlsb_type::BrtEndDbTables15: + return fmt::format_to(ctx.out(), "BrtEndDbTables15"); + case xlsb_type::BrtDbTable15: + return fmt::format_to(ctx.out(), "BrtDbTable15"); + case xlsb_type::BrtBeginDataModel: + return fmt::format_to(ctx.out(), "BrtBeginDataModel"); + case xlsb_type::BrtEndDataModel: + return fmt::format_to(ctx.out(), "BrtEndDataModel"); + case xlsb_type::BrtBeginModelTables: + return fmt::format_to(ctx.out(), "BrtBeginModelTables"); + case xlsb_type::BrtEndModelTables: + return fmt::format_to(ctx.out(), "BrtEndModelTables"); + case xlsb_type::BrtModelTable: + return fmt::format_to(ctx.out(), "BrtModelTable"); + case xlsb_type::BrtBeginModelRelationships: + return fmt::format_to(ctx.out(), "BrtBeginModelRelationships"); + case xlsb_type::BrtEndModelRelationships: + return fmt::format_to(ctx.out(), "BrtEndModelRelationships"); + case xlsb_type::BrtModelRelationship: + return fmt::format_to(ctx.out(), "BrtModelRelationship"); + case xlsb_type::BrtBeginECTxtWiz15: + return fmt::format_to(ctx.out(), "BrtBeginECTxtWiz15"); + case xlsb_type::BrtEndECTxtWiz15: + return fmt::format_to(ctx.out(), "BrtEndECTxtWiz15"); + case xlsb_type::BrtBeginECTWFldInfoLst15: + return fmt::format_to(ctx.out(), "BrtBeginECTWFldInfoLst15"); + case xlsb_type::BrtEndECTWFldInfoLst15: + return fmt::format_to(ctx.out(), "BrtEndECTWFldInfoLst15"); + case xlsb_type::BrtBeginECTWFldInfo15: + return fmt::format_to(ctx.out(), "BrtBeginECTWFldInfo15"); + case xlsb_type::BrtFieldListActiveItem: + return fmt::format_to(ctx.out(), "BrtFieldListActiveItem"); + case xlsb_type::BrtPivotCacheIdVersion: + return fmt::format_to(ctx.out(), "BrtPivotCacheIdVersion"); + case xlsb_type::BrtSXDI15: + return fmt::format_to(ctx.out(), "BrtSXDI15"); + case xlsb_type::brtBeginModelTimeGroupings: + return fmt::format_to(ctx.out(), "brtBeginModelTimeGroupings"); + case xlsb_type::brtEndModelTimeGroupings: + return fmt::format_to(ctx.out(), "brtEndModelTimeGroupings"); + case xlsb_type::brtBeginModelTimeGrouping: + return fmt::format_to(ctx.out(), "brtBeginModelTimeGrouping"); + case xlsb_type::brtEndModelTimeGrouping: + return fmt::format_to(ctx.out(), "brtEndModelTimeGrouping"); + case xlsb_type::brtModelTimeGroupingCalcCol: + return fmt::format_to(ctx.out(), "brtModelTimeGroupingCalcCol"); + case xlsb_type::brtRevisionPtr: + return fmt::format_to(ctx.out(), "brtRevisionPtr"); + case xlsb_type::BrtBeginDynamicArrayPr: + return fmt::format_to(ctx.out(), "BrtBeginDynamicArrayPr"); + case xlsb_type::BrtEndDynamicArrayPr: + return fmt::format_to(ctx.out(), "BrtEndDynamicArrayPr"); + case xlsb_type::BrtBeginRichValueBlock: + return fmt::format_to(ctx.out(), "BrtBeginRichValueBlock"); + case xlsb_type::BrtEndRichValueBlock: + return fmt::format_to(ctx.out(), "BrtEndRichValueBlock"); + case xlsb_type::BrtBeginRichFilters: + return fmt::format_to(ctx.out(), "BrtBeginRichFilters"); + case xlsb_type::BrtEndRichFilters: + return fmt::format_to(ctx.out(), "BrtEndRichFilters"); + case xlsb_type::BrtRichFilter: + return fmt::format_to(ctx.out(), "BrtRichFilter"); + case xlsb_type::BrtBeginRichFilterColumn: + return fmt::format_to(ctx.out(), "BrtBeginRichFilterColumn"); + case xlsb_type::BrtEndRichFilterColumn: + return fmt::format_to(ctx.out(), "BrtEndRichFilterColumn"); + case xlsb_type::BrtBeginCustomRichFilters: + return fmt::format_to(ctx.out(), "BrtBeginCustomRichFilters"); + case xlsb_type::BrtEndCustomRichFilters: + return fmt::format_to(ctx.out(), "BrtEndCustomRichFilters"); + case xlsb_type::BRTCustomRichFilter: + return fmt::format_to(ctx.out(), "BRTCustomRichFilter"); + case xlsb_type::BrtTop10RichFilter: + return fmt::format_to(ctx.out(), "BrtTop10RichFilter"); + case xlsb_type::BrtDynamicRichFilter: + return fmt::format_to(ctx.out(), "BrtDynamicRichFilter"); + case xlsb_type::BrtBeginRichSortCondition: + return fmt::format_to(ctx.out(), "BrtBeginRichSortCondition"); + case xlsb_type::BrtEndRichSortCondition: + return fmt::format_to(ctx.out(), "BrtEndRichSortCondition"); + case xlsb_type::BrtRichFilterDateGroupItem: + return fmt::format_to(ctx.out(), "BrtRichFilterDateGroupItem"); + case xlsb_type::BrtBeginCalcFeatures: + return fmt::format_to(ctx.out(), "BrtBeginCalcFeatures"); + case xlsb_type::BrtEndCalcFeatures: + return fmt::format_to(ctx.out(), "BrtEndCalcFeatures"); + case xlsb_type::BrtCalcFeature: + return fmt::format_to(ctx.out(), "BrtCalcFeature"); + case xlsb_type::BrtExternalLinksPr: + return fmt::format_to(ctx.out(), "BrtExternalLinksPr"); + default: + return fmt::format_to(ctx.out(), "{}", (unsigned int)t); + } + } +}; + +struct brt_bundle_sh { + uint32_t hsState; + uint32_t iTabID; +}; + +#pragma pack(push,1) + +struct brt_row_hdr { + uint32_t rw; + uint32_t ixfe; + uint16_t miyRw; + // FIXME - make sure bitfields are in correct order + uint16_t fExtraAsc : 1; + uint16_t fExtraDsc : 1; + uint16_t reserved1 : 6; + uint16_t iOutLevel : 3; + uint16_t fCollapsed : 1; + uint16_t fDyZero : 1; + uint16_t fUnsynced : 1; + uint16_t fGhostDirty : 1; + uint16_t fReserved : 1; + uint8_t fPhShow : 1; + uint8_t reserved2 : 7; + uint32_t ccolspan; +}; + +struct xlsb_cell { + uint32_t column; + uint32_t iStyleRef : 24; + uint32_t fPhShow : 1; + uint32_t reserved : 7; +}; + +struct rk_number { + uint32_t fx100 : 1; + uint32_t fInt : 1; + uint32_t num : 30; +}; + +#pragma pack(pop) + +struct brt_cell_rk { + xlsb_cell cell; + rk_number value; +}; + +struct brt_cell_bool { + xlsb_cell cell; + uint8_t fBool; +}; + +struct brt_cell_real { + xlsb_cell cell; + double xnum; +}; + +struct brt_cell_st { + xlsb_cell cell; + uint32_t len; + char16_t str[0]; +}; + +#pragma pack(push,1) + +struct rich_str { + uint8_t fRichStr : 1; + uint8_t fExtStr : 1; + uint8_t unused1 : 6; + uint32_t len; + char16_t str[0]; +}; + +#pragma pack(pop) + +struct brt_sst_item { + rich_str richStr; +}; + +struct brt_cell_rstring { + xlsb_cell cell; + rich_str value; +}; + +struct brt_cell_isst { + xlsb_cell cell; + uint32_t isst; +}; + +#pragma pack(push,1) + +struct brt_xf { + uint16_t ixfeParent; + uint16_t iFmt; + uint16_t iFont; + uint16_t iFill; + uint16_t ixBOrder; + uint8_t trot; + uint8_t indent; + uint16_t f123Prefix : 1; + uint16_t fSxButton : 1; + uint16_t fHidden : 1; + uint16_t fLocked : 1; + uint16_t iReadingOrder : 2; + uint16_t fMergeCell : 1; + uint16_t fShrinkToFit : 1; + uint16_t fJustLast : 1; + uint16_t fWrap : 1; + uint16_t alcv : 3; + uint16_t alc : 3; + uint16_t unused : 10; + uint16_t xfGrbitAtr : 6; +}; + +#pragma pack(pop) + +struct brt_wb_prop { + uint32_t f1904 : 1; + uint32_t reserved1 : 1; + uint32_t fHideBorderUnselLists : 1; + uint32_t fFilterPrivacy : 1; + uint32_t fBuggedUserABoutSolution : 1; + uint32_t fShowInkAnnotation : 1; + uint32_t fBackup : 1; + uint32_t fNoSaveSup : 1; + uint32_t grbitUpdateLinks : 2; + uint32_t fHidePivotTableFList : 1; + uint32_t fPublishedBookItems : 1; + uint32_t fCheckCompat : 1; + uint32_t mdDspObj : 2; + uint32_t fShowPivotChartFilter : 1; + uint32_t fAutoCompressPictures : 1; + uint32_t reserved2 : 1; + uint32_t fRefreshAll : 1; + uint32_t unused : 13; + uint32_t dwThemeVersion; + uint32_t strName_len; +}; + +#pragma pack(push,1) + +struct brt_fmt { + uint16_t ifmt; + uint32_t stFmtCode_len; + char16_t stFmtCode[0]; +}; + +#pragma pack(pop) diff --git a/src/xlcpp/xml-reader.cpp b/src/xlcpp/xml-reader.cpp new file mode 100644 index 000000000..baaca6d79 --- /dev/null +++ b/src/xlcpp/xml-reader.cpp @@ -0,0 +1,398 @@ +#include "openxlsx2.h" + +#include "xlcpp-pimpl.h" +#include + +using namespace std; + +static bool __inline is_whitespace(char c) { + return c == ' ' || c == '\t' || c == '\r' || c == '\n'; +} + +static void parse_attributes(string_view node, const function& func) { + auto s = node.substr(1, node.length() - 2); + + if (!s.empty() && s.back() == '/') { + s.remove_suffix(1); + } + + while (!s.empty() && !is_whitespace(s.front())) { + s.remove_prefix(1); + } + + while (!s.empty() && is_whitespace(s.front())) { + s.remove_prefix(1); + } + + while (!s.empty()) { + auto av = s; + + auto eq = av.find_first_of('='); + string_view n, v; + + if (eq == string::npos) { + n = av; + v = ""; + } else { + n = av.substr(0, eq); + v = av.substr(eq + 1); + + while (!v.empty() && is_whitespace(v.front())) { + v = v.substr(1); + } + + if (v.length() >= 2 && (v.front() == '"' || v.front() == '\'')) { + auto c = v.front(); + + v.remove_prefix(1); + + auto end = v.find_first_of(c); + + if (end != string::npos) { + v = v.substr(0, end); + av = av.substr(0, v.data() + v.length() - av.data() + 1); + } else { + for (size_t i = 0; i < av.length(); i++) { + if (is_whitespace(av[i])) { + av = av.substr(0, i); + break; + } + } + } + } + } + + while (!n.empty() && is_whitespace(n.back())) { + n.remove_suffix(1); + } + + if (!func(n, v)) + return; + + s.remove_prefix(av.length()); + + while (!s.empty() && is_whitespace(s.front())) { + s.remove_prefix(1); + } + } +} + +bool xml_reader::read() { + if (sv.empty()) + return false; + + // FIXME - DOCTYPE (, ]>) + + if (type == xml_node::element && empty_tag) + namespaces.pop_back(); + + if (sv.front() != '<') { // text + auto pos = sv.find_first_of('<'); + + if (pos == string::npos) { + node = sv; + sv = ""; + } else { + node = sv.substr(0, pos); + sv = sv.substr(pos); + } + + type = xml_node::whitespace; + + for (auto c : sv) { + if (!is_whitespace(c)) { + type = xml_node::text; + break; + } + } + } else { + if (sv.starts_with(""); + + if (pos == string::npos) { + node = sv; + sv = ""; + } else { + node = sv.substr(0, pos + 2); + sv = sv.substr(pos + 2); + } + + type = xml_node::processing_instruction; + } else if (sv.starts_with("'); + + if (pos == string::npos) { + node = sv; + sv = ""; + } else { + node = sv.substr(0, pos + 1); + sv = sv.substr(pos + 1); + } + + type = xml_node::end_element; + namespaces.pop_back(); + } else if (sv.starts_with(""); + + if (pos == string::npos) + Rcpp::stop("Malformed comment."); + + node = sv.substr(0, pos + 3); + sv = sv.substr(pos + 3); + + type = xml_node::comment; + } else if (sv.starts_with(""); + + if (pos == string::npos) + Rcpp::stop("Malformed CDATA."); + + node = sv.substr(0, pos + 3); + sv = sv.substr(pos + 3); + + type = xml_node::cdata; + } else { + auto pos = sv.find_first_of('>'); + + if (pos == string::npos) { + node = sv; + sv = ""; + } else { + node = sv.substr(0, pos + 1); + sv = sv.substr(pos + 1); + } + + type = xml_node::element; + ns_list ns; + + parse_attributes(node, [&](string_view name, xml_enc_string_view value) { + if (name.starts_with("xmlns:")) + ns.emplace_back(name.substr(6), value); + else if (name == "xmlns") + ns.emplace_back("", value); + + return true; + }); + + namespaces.push_back(ns); + + empty_tag = node.ends_with("/>"); + } + } + + return true; +} + +enum xml_node xml_reader::node_type() const { + return type; +} + +bool xml_reader::is_empty() const { + return type == xml_node::element && empty_tag; +} + +void xml_reader::attributes_loop_raw(const function& func) const { + if (type != xml_node::element) + return; + + parse_attributes(node, [&](string_view name, xml_enc_string_view value_raw) { + auto colon = name.find_first_of(':'); + + if (colon == string::npos) + return func(name, xml_enc_string_view{}, value_raw); + + auto prefix = name.substr(0, colon); + + for (auto it = namespaces.rbegin(); it != namespaces.rend(); it++) { + for (const auto& v : *it) { + if (v.first == prefix) + return func(name.substr(colon + 1), v.second, value_raw); + } + } + + return func(name.substr(colon + 1), xml_enc_string_view{}, value_raw); + }); +} + +optional xml_reader::get_attribute(string_view name, string_view ns) const { + if (type != xml_node::element) + return nullopt; + + optional xesv; + + attributes_loop_raw([&](string_view local_name, xml_enc_string_view namespace_uri_raw, + xml_enc_string_view value_raw) { + if (local_name == name && namespace_uri_raw.cmp(ns)) { + xesv = value_raw; + return false; + } + + return true; + }); + + return xesv; +} + +xml_enc_string_view xml_reader::namespace_uri_raw() const { + auto tag = name(); + auto colon = tag.find_first_of(':'); + string_view prefix; + + if (colon != string::npos) + prefix = tag.substr(0, colon); + + for (auto it = namespaces.rbegin(); it != namespaces.rend(); it++) { + for (const auto& v : *it) { + if (v.first == prefix) + return v.second; + } + } + + return {}; +} + +string_view xml_reader::name() const { + if (type != xml_node::element && type != xml_node::end_element) + return ""; + + auto tag = node.substr(type == xml_node::end_element ? 2 : 1); + + tag.remove_suffix(1); + + for (size_t i = 0; i < tag.length(); i++) { + if (is_whitespace(tag[i])) { + tag = tag.substr(0, i); + break; + } + } + + return tag; +} + +string_view xml_reader::local_name() const { + if (type != xml_node::element && type != xml_node::end_element) + return ""; + + auto tag = name(); + auto pos = tag.find_first_of(':'); + + if (pos == string::npos) + return tag; + else + return tag.substr(pos + 1); +} + +string xml_reader::value() const { + switch (type) { + case xml_node::text: + return xml_enc_string_view{node}.decode(); + + case xml_node::cdata: + return string{node.substr(9, node.length() - 12)}; + + default: + return {}; + } +} + +static string esc_char(string_view s) { + uint32_t c = 0; + from_chars_result fcr; + + if (s.starts_with("x")) + fcr = from_chars(s.data() + 1, s.data() + s.length(), c, 16); + else + fcr = from_chars(s.data(), s.data() + s.length(), c); + + if (c == 0 || c > 0x10ffff) + return ""; + + if (c < 0x80) + return string{(char)c, 1}; + else if (c < 0x800) { + char t[2]; + + t[0] = (char)(0xc0 | (c >> 6)); + t[1] = (char)(0x80 | (c & 0x3f)); + + return string{string_view(t, 2)}; + } else if (c < 0x10000) { + char t[3]; + + t[0] = (char)(0xe0 | (c >> 12)); + t[1] = (char)(0x80 | ((c >> 6) & 0x3f)); + t[2] = (char)(0x80 | (c & 0x3f)); + + return string{string_view(t, 3)}; + } else { + char t[4]; + + t[0] = (char)(0xf0 | (c >> 18)); + t[1] = (char)(0x80 | ((c >> 12) & 0x3f)); + t[2] = (char)(0x80 | ((c >> 6) & 0x3f)); + t[3] = (char)(0x80 | (c & 0x3f)); + + return string{string_view(t, 4)}; + } +} + +string xml_enc_string_view::decode() const { + auto v = sv; + string s; + + s.reserve(v.length()); + + while (!v.empty()) { + if (v.front() == '&') { + v.remove_prefix(1); + + if (v.starts_with("amp;")) { + s += "&"; + v.remove_prefix(4); + } else if (v.starts_with("lt;")) { + s += "<"; + v.remove_prefix(3); + } else if (v.starts_with("gt;")) { + s += ">"; + v.remove_prefix(3); + } else if (v.starts_with("quot;")) { + s += "\""; + v.remove_prefix(5); + } else if (v.starts_with("apos;")) { + s += "'"; + v.remove_prefix(5); + } else if (v.starts_with("#")) { + string_view bit; + + v.remove_prefix(1); + + auto sc = v.find_first_of(';'); + if (sc == string::npos) { + bit = v; + v = ""; + } else { + bit = v.substr(0, sc); + v.remove_prefix(sc + 1); + } + + s += esc_char(bit); + } else + s += "&"; + } else { + s += v.front(); + v.remove_prefix(1); + } + } + + return s; +} + +bool xml_enc_string_view::cmp(string_view str) const { + for (auto c : sv) { + if (c == '&') + return decode() == str; + } + + return sv == str; +} diff --git a/src/xlcpp/xml-writer.cpp b/src/xlcpp/xml-writer.cpp new file mode 100644 index 000000000..421d0d992 --- /dev/null +++ b/src/xlcpp/xml-writer.cpp @@ -0,0 +1,77 @@ +#include "xlcpp-pimpl.h" + +using namespace std; + +string xml_writer::dump() const { + return buf; +} + +void xml_writer::start_document() { + buf += "\n"; + empty_tag = false; +} + +static string xml_escape(string_view s, bool att) { + string ret; + + ret.reserve(s.length()); + + for (auto c : s) { + if (c == '<') + ret += "<"; + else if (c == '>') + ret += ">"; + else if (c == '&') + ret += "&"; + else if (c == '"' && att) + ret += """; + else + ret += c; + } + + return ret; +} + +void xml_writer::start_element(string_view tag, const unordered_map& namespaces) { + if (empty_tag) + buf += ">"; + + buf += "<" + string{tag}; + tags.emplace(tag); + + empty_tag = true; + + for (const auto& ns : namespaces) { + buf += " xmlns"; + + if (!ns.first.empty()) + buf += ":" + ns.first; + + buf += "=\""; + buf += xml_escape(ns.second, true); + buf += "\""; + } +} + +void xml_writer::end_element() { + if (empty_tag) { + buf += "/>"; + empty_tag = false; + } else + buf += ""; + + tags.pop(); +} + +void xml_writer::text(string_view s) { + if (empty_tag) { + buf += ">"; + empty_tag = false; + } + + buf += xml_escape(s, false); +} + +void xml_writer::attribute(string_view name, string_view value) { + buf += " " + string{name} + "=\"" + xml_escape(value, true) + "\""; +} diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R index 549a31fc6..b4fc1ab2d 100644 --- a/tests/testthat/helper.R +++ b/tests/testthat/helper.R @@ -1021,7 +1021,8 @@ download_testfiles <- function() { "umlauts.xlsx", "unemployment-nrw202208.xlsx", "update_test.xlsx", - "vml_numbering.xlsx" + "vml_numbering.xlsx", + "openxlsx2_example_pass.xlsx" ) test_path <- testthat::test_path("testfiles") diff --git a/tests/testthat/test-loading_workbook.R b/tests/testthat/test-loading_workbook.R index 8668a9e22..e75c17ea1 100644 --- a/tests/testthat/test-loading_workbook.R +++ b/tests/testthat/test-loading_workbook.R @@ -397,3 +397,15 @@ test_that("sheetView is not switched", { expect_equal(exp, got) }) + +test_that("loading password protected workbooks works", { + + fl <- testfile_path("openxlsx2_example_pass.xlsx") + + wb <- wb_load(fl, password = "openxlsx2") + + exp <- c(10, 9) + got <- dim(wb_to_df(wb)) + expect_equal(exp, got) + +}) From ec1a54ed66bcbdd0a4ff9ccf28fec981288f8717 Mon Sep 17 00:00:00 2001 From: Jan Marvin Garbuszus Date: Sat, 15 Jul 2023 14:50:36 +0200 Subject: [PATCH 2/9] add libfmt --- .gitignore | 1 + DESCRIPTION | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index bceedb8d6..5096ee10c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ .DS_Store .vscode/* src/*.o +src/xlcpp/*.o src/*.so src/*.dll src-i386/*.dll diff --git a/DESCRIPTION b/DESCRIPTION index 40b2ff2fb..984c1224b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -44,4 +44,4 @@ Config/testthat/edition: 3 Config/testthat/parallel: false Config/testthat/start-first: aaa SystemRequirements: C++20, libarchive: libarchive-dev (deb), - libarchive-devel (rpm), libarchive (homebrew), libarchive_dev (csw) + libarchive-devel (rpm), libarchive (homebrew), libarchive_dev (csw), libfmt: libfmt-dev (deb), fmt (homebrew) From f4cdcea755e02bb396ee733f5b2dd52f336bcc61 Mon Sep 17 00:00:00 2001 From: Jan Marvin Garbuszus Date: Sun, 16 Jul 2023 21:57:47 +0200 Subject: [PATCH 3/9] remove --- src/Makevars | 11 +- src/Makevars.in | 11 +- src/xlcpp/cfbf.cpp | 1 - src/xlcpp/xlcpp-pimpl.h | 237 ---- src/xlcpp/xlcpp.cpp | 1928 +-------------------------- src/xlcpp/xlcpp.h | 133 +- src/xlcpp/xlsb.cpp | 565 -------- src/xlcpp/xlsb.h | 2707 -------------------------------------- src/xlcpp/xml-reader.cpp | 60 - src/xlcpp/xml-writer.cpp | 77 -- 10 files changed, 33 insertions(+), 5697 deletions(-) delete mode 100644 src/xlcpp/xlsb.cpp delete mode 100644 src/xlcpp/xlsb.h delete mode 100644 src/xlcpp/xml-writer.cpp diff --git a/src/Makevars b/src/Makevars index 49045080d..f3cae4a92 100644 --- a/src/Makevars +++ b/src/Makevars @@ -3,7 +3,7 @@ PKG_CXXFLAGS = -I. -Ixlcpp -I../inst/include/pugixml -DXLCPP_EXPORT #PKG_LIBS=-Lpugixml -Lcfbf -L/usr/lib -larchive -L/usr/lib -lfmt -PKG_LIBS = -larchive -Lpugixml -Lxlcpp -lfmt +PKG_LIBS = -larchive -Lpugixml -Lxlcpp PKGROOT = ./xlcpp @@ -21,21 +21,18 @@ OBJECTS = decrypt.o \ $(PKGROOT)/sha1.o \ $(PKGROOT)/sha512.o \ $(PKGROOT)/xlcpp.o \ - $(PKGROOT)/xlsb.o \ $(PKGROOT)/xml-reader.o \ - $(PKGROOT)/xml-writer.o \ RcppExports.o + XLCPP = $(PKGROOT)/aes.cpp \ $(PKGROOT)/b64.cpp \ - $(PKGROOT)/cfbf.cpp \ + $(PKGROOT)/cfbf.cpp \ $(PKGROOT)/mmap.cpp \ $(PKGROOT)/sha1.cpp \ $(PKGROOT)/sha512.cpp \ $(PKGROOT)/xml-reader.cpp \ - $(PKGROOT)/xml-writer.cpp \ - $(PKGROOT)/xlcpp.cpp \ - $(PKGROOT)/xlsb.cpp + $(PKGROOT)/xlcpp.cpp PUGIXML = ../inst/include/pugixml/pugixml.cpp diff --git a/src/Makevars.in b/src/Makevars.in index ca584e421..4da22aace 100644 --- a/src/Makevars.in +++ b/src/Makevars.in @@ -3,7 +3,7 @@ PKG_CXXFLAGS = @PKG_CXXFLAGS@ -I. -Ixlcpp -I../inst/include/pugixml -DXLCPP_EXPORT #PKG_LIBS=-Lpugixml -Lcfbf -L/usr/lib -larchive -L/usr/lib -lfmt -PKG_LIBS = @PKG_LIBS@ -Lpugixml -Lxlcpp -lfmt +PKG_LIBS = @PKG_LIBS@ -Lpugixml -Lxlcpp PKGROOT = ./xlcpp @@ -21,21 +21,18 @@ OBJECTS = decrypt.o \ $(PKGROOT)/sha1.o \ $(PKGROOT)/sha512.o \ $(PKGROOT)/xlcpp.o \ - $(PKGROOT)/xlsb.o \ $(PKGROOT)/xml-reader.o \ - $(PKGROOT)/xml-writer.o \ RcppExports.o + XLCPP = $(PKGROOT)/aes.cpp \ $(PKGROOT)/b64.cpp \ - $(PKGROOT)/cfbf.cpp \ + $(PKGROOT)/cfbf.cpp \ $(PKGROOT)/mmap.cpp \ $(PKGROOT)/sha1.cpp \ $(PKGROOT)/sha512.cpp \ $(PKGROOT)/xml-reader.cpp \ - $(PKGROOT)/xml-writer.cpp \ - $(PKGROOT)/xlcpp.cpp \ - $(PKGROOT)/xlsb.cpp + $(PKGROOT)/xlcpp.cpp PUGIXML = ../inst/include/pugixml/pugixml.cpp diff --git a/src/xlcpp/cfbf.cpp b/src/xlcpp/cfbf.cpp index 94896d1dc..4811f05b2 100644 --- a/src/xlcpp/cfbf.cpp +++ b/src/xlcpp/cfbf.cpp @@ -1,6 +1,5 @@ #include "openxlsx2.h" -#include #include #include #include "cfbf.h" diff --git a/src/xlcpp/xlcpp-pimpl.h b/src/xlcpp/xlcpp-pimpl.h index f3614fcd4..f3325d12a 100644 --- a/src/xlcpp/xlcpp-pimpl.h +++ b/src/xlcpp/xlcpp-pimpl.h @@ -13,7 +13,6 @@ #include #include #include -#include namespace xlcpp { @@ -26,106 +25,22 @@ typedef struct { std::string data; } file; -class font { -public: - font(std::string_view font_name, unsigned int font_size, bool bold) : font_name(font_name), font_size(font_size), bold(bold) { } - - std::string font_name; - unsigned int font_size; - bool bold; -}; - -class font_hash { -public: - size_t operator()(const font& f) const { - return std::hash{}(f.font_name) | - (std::hash{}(f.font_size) << 1) | - (std::hash{}(f.bold) << 2); - } -}; - -bool operator==(const font& lhs, const font& rhs) noexcept; - -class style { -public: - style(std::string_view number_format, std::string_view font, unsigned int font_size, bool bold = false) : - number_format(number_format), font(font, font_size, bold) { } - - void set_font(std::string_view font_name, unsigned int font_size, bool bold); - void set_number_format(std::string_view fmt); - - std::string number_format; - xlcpp::font font; - - mutable unsigned int num; - mutable unsigned int number_format_num; -}; - -class style_hash { -public: - size_t operator()(const style& s) const { - return std::hash{}(s.number_format) | - (font_hash{}(s.font) << 1); - } -}; - -bool operator==(const style& lhs, const style& rhs) noexcept; class workbook_pimpl { public: workbook_pimpl() = default; workbook_pimpl(const std::filesystem::path& fn, std::string_view password, std::string_view outfile); workbook_pimpl(std::span sv, std::string_view password, std::string_view outfile); - sheet& add_sheet(std::string_view name, bool visible); - void save(const std::filesystem::path& fn) const; std::string data() const; - void write_workbook_xml(struct archive* a) const; - void write_content_types_xml(struct archive* a) const; - void write_rels(struct archive* a) const; - void write_workbook_rels(struct archive* a) const; - shared_string get_shared_string(std::string_view s); - void write_shared_strings(struct archive* a) const; - void write_styles(struct archive* a) const; void write_archive(struct archive* a) const; la_ssize_t write_callback(struct archive* a, const void* buffer, size_t length) const; - void parse_workbook(std::string_view fn, std::string_view data, - const std::unordered_map& files); - void parse_workbook_binary(std::string_view fn, std::span data, - const std::unordered_map& files); - void load_sheet(std::string_view name, std::string_view data, bool visible); - void load_sheet_binary(std::string_view name, std::span data, bool visible); - void load_shared_strings2(std::string_view sv); - void load_shared_strings_binary(std::span data); - void load_shared_strings(const std::unordered_map& files); - void load_styles(const std::unordered_map& files); - void load_styles2(std::string_view sv); - void load_styles_binary(std::span data); - std::string find_number_format(unsigned int num); void load_archive(struct archive* a); #ifdef _WIN32 void rename(const std::filesystem::path& fn) const; #endif - template - const style* find_style(Args&&... args) { - auto ret = styles.emplace(args...); - - if (ret.second) - ret.first->num = (unsigned int)(styles.size() - 1); - - return &(*ret.first); - } - - std::list sheets; - std::map> shared_strings; - std::vector shared_strings2; - std::unordered_set styles; - std::unordered_map number_formats; - std::vector> cell_styles; - bool date1904 = false; - mutable std::string buf; #ifdef _WIN32 @@ -138,72 +53,6 @@ class workbook_pimpl { void load_from_memory(std::span sv, std::string_view password, std::string_view outfile); }; -class sheet_pimpl { -public: - sheet_pimpl(workbook_pimpl& wb, std::string_view name, unsigned int num, bool visible) : parent(wb), name(name), num(num), visible(visible) { } - - void write(struct archive* a) const; - std::string xml() const; - row& add_row(); - - workbook_pimpl& parent; - std::string name; - unsigned int num; - bool visible; - std::list rows; -}; - -class row_pimpl { -public: - row_pimpl(sheet_pimpl& s, unsigned int num) : parent(s), num(num) { } - - template - cell& add_cell(const T& val) { - return *cells.emplace(cells.end(), *this, cells.size() + 1, val); - } - - sheet_pimpl& parent; - unsigned int num; - std::list cells; -}; - -class cell_pimpl { -public: - template - cell_pimpl(row_pimpl& r, unsigned int num, const T& t); - - cell_pimpl(row_pimpl& r, unsigned int num, std::string_view t); - cell_pimpl(row_pimpl& r, unsigned int num, const std::chrono::system_clock::time_point& val) : cell_pimpl(r, num, datetime{val}) { } - - void set_number_format(std::string_view fmt); - void set_font(std::string_view name, unsigned int size, bool bold = false); - - row_pimpl& parent; - - const style* sty; - - unsigned int num; - std::variant val; - std::string number_format; -}; - -}; - -class xml_writer { -public: - std::string dump() const; - void start_document(); - void start_element(std::string_view tag, const std::unordered_map& namespaces = {}); - void end_element(); - void text(std::string_view s); - void attribute(std::string_view name, std::string_view value); - -private: - std::string buf; - std::stack tags; - bool empty_tag; -}; - enum class xml_node { unknown, text, @@ -215,41 +64,6 @@ enum class xml_node { cdata }; -template<> -struct fmt::formatter { - constexpr auto parse(format_parse_context& ctx) { - auto it = ctx.begin(); - - if (it != ctx.end() && *it != '}') - throw format_error("invalid format"); - - return it; - } - - template - auto format(enum xml_node n, format_context& ctx) const { - switch (n) { - case xml_node::unknown: - return fmt::format_to(ctx.out(), "unknown"); - case xml_node::text: - return fmt::format_to(ctx.out(), "text"); - case xml_node::whitespace: - return fmt::format_to(ctx.out(), "whitespace"); - case xml_node::element: - return fmt::format_to(ctx.out(), "element"); - case xml_node::end_element: - return fmt::format_to(ctx.out(), "end_element"); - case xml_node::processing_instruction: - return fmt::format_to(ctx.out(), "processing_instruction"); - case xml_node::comment: - return fmt::format_to(ctx.out(), "comment"); - case xml_node::cdata: - return fmt::format_to(ctx.out(), "cdata"); - default: - return fmt::format_to(ctx.out(), "{:x}", (unsigned int)n); - } - } -}; class xml_enc_string_view { public: @@ -311,54 +125,3 @@ class archive_write_closer { }; using archive_write_t = std::unique_ptr; - - -static constexpr std::chrono::year_month_day number_to_date(unsigned int num, bool date1904) noexcept { - unsigned int J = num + 2415019; - unsigned int f, e, g, h; - unsigned int day, month; - int year; - - if (date1904) - J += 1462; - else if (num < 61) // Excel's 29/2/1900 bug - J++; - - f = J; - f *= 4; - f += 274277; - f /= 146097; - f *= 3; - f /= 4; - f += J; - f += 1363; - - e = (f * 4) + 3; - - g = e % 1461; - g /= 4; - - h = (5 * g) + 2; - - day = h % 153; - day /= 5; - day++; - - month = h; - month /= 153; - month += 2; - month %= 12; - month++; - - year = 14 - month; - year /= 12; - year -= 4716; - year += e / 1461; - - return std::chrono::year_month_day{std::chrono::year{year}, std::chrono::month{month}, std::chrono::day{day}}; -} - -// xlcpp.cpp -bool is_date(std::string_view sv); -bool is_time(std::string_view sv); -std::unordered_map read_relationships(std::string_view fn, const std::unordered_map& files); diff --git a/src/xlcpp/xlcpp.cpp b/src/xlcpp/xlcpp.cpp index d873cb5e7..62bfd58a2 100644 --- a/src/xlcpp/xlcpp.cpp +++ b/src/xlcpp/xlcpp.cpp @@ -17,9 +17,9 @@ #include #endif -#define FMT_HEADER_ONLY -#include -#include +// #define FMT_HEADER_ONLY +// #include +// #include #define BLOCK_SIZE 20480 @@ -34,1701 +34,16 @@ static const string NS_CONTENT_TYPES = "http://schemas.openxmlformats.org/packag #define NUMFMT_OFFSET 165 -static const array builtin_styles = { - pair{ 0, "General" }, - pair{ 1, "0" }, - pair{ 2, "0.00" }, - pair{ 3, "#,##0" }, - pair{ 4, "#,##0.00" }, - pair{ 9, "0%" }, - pair{ 10, "0.00%" }, - pair{ 11, "0.00E+00" }, - pair{ 12, "# ?/?" }, - pair{ 13, "# \?\?/??" }, - pair{ 14, "mm-dd-yy" }, - pair{ 15, "d-mmm-yy" }, - pair{ 16, "d-mmm" }, - pair{ 17, "mmm-yy" }, - pair{ 18, "h:mm AM/PM" }, - pair{ 19, "h:mm:ss AM/PM" }, - pair{ 20, "h:mm" }, - pair{ 21, "h:mm:ss" }, - pair{ 22, "m/d/yy h:mm" }, - pair{ 37, "#,##0 ;(#,##0)" }, - pair{ 38, "#,##0 ;[Red](#,##0)" }, - pair{ 39, "#,##0.00;(#,##0.00)" }, - pair{ 40, "#,##0.00;[Red](#,##0.00)" }, - pair{ 45, "mm:ss" }, - pair{ 46, "[h]:mm:ss" }, - pair{ 47, "mmss.0" }, - pair{ 48, "##0.0E+0" }, - pair{ 49, "@" }, -}; +// static string try_decode(const optional& sv) { +// if (!sv) +// return ""; +// +// return sv.value().decode(); +// } -bool is_date(string_view sv) { - if (sv == "General") - return false; - - string s; - - s.reserve(sv.length()); - - for (auto c : sv) { - if (c >= 'a' && c <= 'z') { - if (s.empty() || s.back() != c) - s += c; - } else if (c >= 'A' && c <= 'Z') { - if (s.empty() || s.back() != c - 'A' + 'a') - s += c - 'A' + 'a'; - } - } - - static const char* patterns[] = { - "dmy", - "ymd", - "mdy", - "my" - }; - - for (const auto& p : patterns) { - if (s.find(p) != string::npos) - return true; - } - - return false; -} - -bool is_time(string_view sv) { - if (sv == "General") - return false; - - string s; - - s.reserve(sv.length()); - - for (auto c : sv) { - if (c >= 'a' && c <= 'z') { - if (s.empty() || s.back() != c) - s += c; - } else if (c >= 'A' && c <= 'Z') { - if (s.empty() || s.back() != c - 'A' + 'a') - s += c - 'A' + 'a'; - } - } - - // FIXME - "h AM/PM" etc. - - return s.find("hm") != string::npos; -} - -static string try_decode(const optional& sv) { - if (!sv) - return ""; - - return sv.value().decode(); -} - -unordered_map read_relationships(string_view fn, const unordered_map& files) { - filesystem::path p = fn; - unordered_map rels; - - p.remove_filename(); - p /= "_rels"; - p /= filesystem::path(fn).filename().string() + ".rels"; - - auto ps = p.string(); - - for (auto& c : ps) { - if (c == '\\') - c = '/'; - } - - if (files.count(ps) == 0) - Rcpp::stop("File {} not found.", ps); - - xml_reader r(files.at(ps).data); - unsigned int depth = 0; - - while (r.read()) { - unsigned int next_depth; - - if (r.node_type() == xml_node::element && !r.is_empty()) - next_depth = depth + 1; - else if (r.node_type() == xml_node::end_element) - next_depth = depth - 1; - else - next_depth = depth; - - if (r.node_type() == xml_node::element) { - if (depth == 0) { - if (r.local_name() != "Relationships" || !r.namespace_uri_raw().cmp(NS_PACKAGE_RELATIONSHIPS)) { - Rcpp::stop("Root tag was {{{}}}{}, expected {{{}}}Relationships.", - r.namespace_uri_raw().decode(), r.local_name(), NS_PACKAGE_RELATIONSHIPS); - } - } else if (depth == 1) { - if (r.local_name() == "Relationship" && r.namespace_uri_raw().cmp(NS_PACKAGE_RELATIONSHIPS)) { - auto id = try_decode(r.get_attribute("Id")); - auto target = try_decode(r.get_attribute("Target")); - - if (!id.empty() && !target.empty()) - rels[id] = target; - } - } - } - - depth = next_depth; - } - - return rels; -} - -namespace xlcpp { - -sheet& workbook_pimpl::add_sheet(string_view name, bool visible) { - return *sheets.emplace(sheets.end(), *this, name, sheets.size() + 1, visible); -} - -sheet& workbook::add_sheet(string_view name, bool visible) { - return impl->add_sheet(name, visible); -} - -class _formatted_error : public exception { -public: - template - _formatted_error(T&& s, Args&&... args) { - msg = fmt::format(s, forward(args)...); - } - - const char* what() const noexcept { - return msg.c_str(); - } - -private: - string msg; -}; - -#define formatted_error(s, ...) _formatted_error(FMT_COMPILE(s), ##__VA_ARGS__) - -static string make_reference(unsigned int row, unsigned int col) { - char colstr[5]; - - col--; - - if (col < 26) { - colstr[0] = (char)(col + 'A'); - colstr[1] = 0; - } else if (col < 702) { - colstr[0] = (char)((col / 26) - 1 + 'A'); - colstr[1] = (char)((col % 26) + 'A'); - colstr[2] = 0; - } else if (col < 16384) { - colstr[0] = (char)((col / 676) - 1 + 'A'); - colstr[1] = (char)(((col / 26) % 26) - 1 + 'A'); - colstr[2] = (char)((col % 26) + 'A'); - colstr[3] = 0; - } else - Rcpp::stop("Column {} too large.", col); - - return string(colstr) + to_string(row); -} - -// hopefully from_chars will be constexpr some day - see P2291R0 -template -requires is_integral_v && is_unsigned_v -static constexpr from_chars_result from_chars_constexpr(const char* first, const char* last, T& t) { - from_chars_result res; - - res.ptr = first; - res.ec = {}; - - t = 0; - - if (first == last || *first < '0' || *first > '9') - return res; - - while (first != last && *first >= '0' && *first <= '9') { - t *= 10; - t += (T)(*first - '0'); - first++; - res.ptr++; - } - - return res; -} - -static constexpr bool resolve_reference(string_view sv, unsigned int& row, unsigned int& col) noexcept { - from_chars_result fcr; - - if (sv.length() >= 2 && sv[0] >= 'A' && sv[0] <= 'Z' && sv[1] >= '0' && sv[1] <= '9') { - col = sv[0] - 'A'; - fcr = from_chars_constexpr(sv.data() + 1, sv.data() + sv.length(), row); - } else if (sv.length() >= 3 && sv[0] >= 'A' && sv[0] <= 'Z' && sv[1] >= 'A' && sv[1] <= 'Z' && sv[2] >= '0' && sv[2] <= '9') { - col = ((sv[0] - 'A' + 1) * 26) + sv[1] - 'A'; - fcr = from_chars_constexpr(sv.data() + 2, sv.data() + sv.length(), row); - } else if (sv.length() >= 4 && sv[0] >= 'A' && sv[0] <= 'Z' && sv[1] >= 'A' && sv[1] <= 'Z' && sv[2] >= 'A' && sv[2] <= 'Z' && sv[3] >= '0' && sv[3] <= '9') { - col = ((sv[0] - 'A' + 1) * 676) + ((sv[1] - 'A' + 1) * 26) + sv[2] - 'A'; - fcr = from_chars_constexpr(sv.data() + 3, sv.data() + sv.length(), row); - } else - return false; - - if (fcr.ptr != sv.data() + sv.length()) - return false; - - row--; - - return true; -} - -static constexpr bool test_resolve_reference(string_view sv, bool exp_valid, unsigned int exp_row, - unsigned int exp_col) noexcept { - bool valid; - unsigned int row, col; - - valid = resolve_reference(sv, row, col); - - if (!valid) - return !exp_valid; - else if (!exp_valid) - return false; - - return row == exp_row && col == exp_col; -} - -static_assert(test_resolve_reference("", false, 0, 0)); -static_assert(test_resolve_reference("A", false, 0, 0)); -static_assert(test_resolve_reference("1", false, 0, 0)); -static_assert(test_resolve_reference("A1", true, 0, 0)); -static_assert(test_resolve_reference("D3", true, 2, 3)); -static_assert(test_resolve_reference("Z255", true, 254, 25)); -static_assert(test_resolve_reference("AA", false, 0, 0)); -static_assert(test_resolve_reference("AA1", true, 0, 26)); -static_assert(test_resolve_reference("MH229", true, 228, 345)); -static_assert(test_resolve_reference("ZZ16383", true, 16382, 701)); -static_assert(test_resolve_reference("AAA", false, 0, 0)); -static_assert(test_resolve_reference("AAA1", true, 0, 702)); -static_assert(test_resolve_reference("AMJ1048576", true, 1048575, 1023)); - -static constexpr unsigned int date_to_number(const chrono::year_month_day& ymd, bool date1904) noexcept { - int m2 = ((int)(unsigned int)ymd.month() - 14) / 12; - long long n; - - n = (1461 * ((int)ymd.year() + 4800 + m2)) / 4; - n += (367 * ((int)(unsigned int)ymd.month() - 2 - (12 * m2))) / 12; - n -= (3 * (((int)ymd.year() + 4900 + m2)/100)) / 4; - n += (unsigned int)ymd.day(); - n -= 2447094; - - if (date1904) - n -= 1462; - else if (n < 61) // Excel's 29/2/1900 bug - n--; - - return (unsigned int)n; -} - -static_assert(date_to_number(chrono::year_month_day{1900y, chrono::January, 1d}, false) == 1); -static_assert(date_to_number(chrono::year_month_day{1900y, chrono::February, 28d}, false) == 59); -static_assert(date_to_number(chrono::year_month_day{1900y, chrono::March, 1d}, false) == 61); -static_assert(date_to_number(chrono::year_month_day{1998y, chrono::July, 5d}, false) == 35981); -static_assert(date_to_number(chrono::year_month_day{1998y, chrono::July, 5d}, true) == 34519); - -static_assert(number_to_date(1, false) == chrono::year_month_day{1900y, chrono::January, 1d}); -static_assert(number_to_date(59, false) == chrono::year_month_day{1900y, chrono::February, 28d}); -static_assert(number_to_date(61, false) == chrono::year_month_day{1900y, chrono::March, 1d}); -static_assert(number_to_date(35981, false) == chrono::year_month_day{1998y, chrono::July, 5d}); -static_assert(number_to_date(34519, true) == chrono::year_month_day{1998y, chrono::July, 5d}); - -static constexpr double datetime_to_number(const datetime& dt, bool date1904) noexcept { - return (double)date_to_number(dt.d, date1904) + ((double)dt.t.count() / 86400.0); -} - -template -inline constexpr bool always_false_v = false; - -string sheet_pimpl::xml() const { - xml_writer writer; - - writer.start_document(); - - writer.start_element("worksheet", {{"", NS_SPREADSHEET}}); - - writer.start_element("sheetData"); - - for (const auto& r : rows) { - writer.start_element("row"); - - writer.attribute("r", to_string(r.impl->num)); - writer.attribute("customFormat", "false"); - writer.attribute("ht", "12.8"); - writer.attribute("hidden", "false"); - writer.attribute("customHeight", "false"); - writer.attribute("outlineLevel", "0"); - writer.attribute("collapsed", "false"); - - for (const auto& c : r.impl->cells) { - writer.start_element("c"); - - writer.attribute("r", make_reference(r.impl->num, c.impl->num)); - writer.attribute("s", to_string(c.impl->sty->num)); - - visit([&](auto&& arg) { - using T = decay_t; - - if constexpr (is_same_v) { - writer.attribute("t", "n"); // number - - writer.start_element("v"); - writer.text(to_string(arg)); - writer.end_element(); - } else if constexpr (is_same_v) { - writer.attribute("t", "s"); // shared string - - writer.start_element("v"); - writer.text(to_string(arg.num)); - writer.end_element(); - } else if constexpr (is_same_v) { - writer.attribute("t", "n"); // number - - writer.start_element("v"); - writer.text(to_string(arg)); - writer.end_element(); - } else if constexpr (is_same_v) { - writer.attribute("t", "n"); // number - - writer.start_element("v"); - writer.text(to_string(date_to_number(arg, parent.date1904))); - writer.end_element(); - } else if constexpr (is_same_v) { - auto s = (double)arg.count() / 86400.0; - - writer.attribute("t", "n"); // number - - writer.start_element("v"); - writer.text(to_string(s)); - writer.end_element(); - } else if constexpr (is_same_v) { - writer.attribute("t", "n"); // number - - writer.start_element("v"); - writer.text(to_string(datetime_to_number(arg, parent.date1904))); - writer.end_element(); - } else if constexpr (is_same_v) { - writer.attribute("t", "b"); // bool - - writer.start_element("v"); - writer.text(to_string(arg)); - writer.end_element(); - } else if constexpr (is_same_v) { - // nop - } else if constexpr (is_same_v) { - writer.attribute("t", "str"); - - writer.start_element("v"); - writer.text(arg); // FIXME - Unicode should be encoded - writer.end_element(); - } else - static_assert(always_false_v); - }, c.impl->val); - - writer.end_element(); - } - - writer.end_element(); - } - - writer.end_element(); - - writer.end_element(); - - return writer.dump(); -} - -void sheet_pimpl::write(struct archive* a) const { - struct archive_entry* entry; - string data = xml(); - - entry = archive_entry_new(); - archive_entry_set_pathname(entry, ("xl/worksheets/sheet" + to_string(num) + ".xml").c_str()); - archive_entry_set_size(entry, data.length()); - archive_entry_set_filetype(entry, AE_IFREG); - archive_entry_set_perm(entry, 0644); - archive_write_header(a, entry); - archive_write_data(a, data.data(), data.length()); - // FIXME - set date? - archive_entry_free(entry); -} - -void workbook_pimpl::write_workbook_xml(struct archive* a) const { - struct archive_entry* entry; - string data; - - { - xml_writer writer; - - writer.start_document(); - - writer.start_element("workbook", {{"", NS_SPREADSHEET}, {"r", NS_RELATIONSHIPS}}); - - writer.start_element("workbookPr"); - writer.attribute("date1904", date1904 ? "true" : "false"); - writer.end_element(); - - writer.start_element("sheets"); - - for (const auto& sh : sheets) { - writer.start_element("sheet"); - writer.attribute("name", sh.impl->name); - writer.attribute("sheetId", to_string(sh.impl->num)); - writer.attribute("state", "visible"); - writer.attribute("r:id", "rId" + to_string(sh.impl->num)); - writer.end_element(); - } - - writer.end_element(); - - writer.end_element(); - - data = move(writer.dump()); - } - - entry = archive_entry_new(); - archive_entry_set_pathname(entry, "xl/workbook.xml"); - archive_entry_set_size(entry, data.length()); - archive_entry_set_filetype(entry, AE_IFREG); - archive_entry_set_perm(entry, 0644); - archive_write_header(a, entry); - archive_write_data(a, data.data(), data.length()); - // FIXME - set date? - archive_entry_free(entry); -} - -void workbook_pimpl::write_content_types_xml(struct archive* a) const { - struct archive_entry* entry; - string data; - - { - xml_writer writer; - - writer.start_document(); - - writer.start_element("Types", {{"", NS_CONTENT_TYPES}}); - - writer.start_element("Override"); - writer.attribute("PartName", "/xl/workbook.xml"); - writer.attribute("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"); - writer.end_element(); - - for (const auto& sh : sheets) { - writer.start_element("Override"); - writer.attribute("PartName", "/xl/worksheets/sheet" + to_string(sh.impl->num) + ".xml"); - writer.attribute("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"); - writer.end_element(); - } - - writer.start_element("Override"); - writer.attribute("PartName", "/_rels/.rels"); - writer.attribute("ContentType", "application/vnd.openxmlformats-package.relationships+xml"); - writer.end_element(); - - writer.start_element("Override"); - writer.attribute("PartName", "/xl/_rels/workbook.xml.rels"); - writer.attribute("ContentType", "application/vnd.openxmlformats-package.relationships+xml"); - writer.end_element(); - - if (!shared_strings.empty()) { - writer.start_element("Override"); - writer.attribute("PartName", "/xl/sharedStrings.xml"); - writer.attribute("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"); - writer.end_element(); - } - - if (!styles.empty()) { - writer.start_element("Override"); - writer.attribute("PartName", "/xl/styles.xml"); - writer.attribute("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"); - writer.end_element(); - } - - writer.end_element(); - - data = move(writer.dump()); - } - - entry = archive_entry_new(); - archive_entry_set_pathname(entry, "[Content_Types].xml"); - archive_entry_set_size(entry, data.length()); - archive_entry_set_filetype(entry, AE_IFREG); - archive_entry_set_perm(entry, 0644); - archive_write_header(a, entry); - archive_write_data(a, data.data(), data.length()); - // FIXME - set date? - archive_entry_free(entry); -} - -void workbook_pimpl::write_rels(struct archive* a) const { - struct archive_entry* entry; - string data; - - { - xml_writer writer; - - writer.start_document(); - - writer.start_element("Relationships", {{"", "http://schemas.openxmlformats.org/package/2006/relationships"}}); - - writer.start_element("Relationship"); - writer.attribute("Id", "rId1"); - writer.attribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"); - writer.attribute("Target", "/xl/workbook.xml"); - writer.end_element(); - - writer.end_element(); - - data = move(writer.dump()); - } - - entry = archive_entry_new(); - archive_entry_set_pathname(entry, "_rels/.rels"); - archive_entry_set_size(entry, data.length()); - archive_entry_set_filetype(entry, AE_IFREG); - archive_entry_set_perm(entry, 0644); - archive_write_header(a, entry); - archive_write_data(a, data.data(), data.length()); - // FIXME - set date? - archive_entry_free(entry); -} - -void workbook_pimpl::write_workbook_rels(struct archive* a) const { - struct archive_entry* entry; - string data; - - { - unsigned int num = 1; - xml_writer writer; - - writer.start_document(); - - writer.start_element("Relationships", {{"", "http://schemas.openxmlformats.org/package/2006/relationships"}}); - - for (const auto& sh : sheets) { - writer.start_element("Relationship"); - writer.attribute("Id", "rId" + to_string(num)); - writer.attribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"); - writer.attribute("Target", "worksheets/sheet" + to_string(sh.impl->num) + ".xml"); - writer.end_element(); - num++; - } - - if (!shared_strings.empty()) { - writer.start_element("Relationship"); - writer.attribute("Id", "rId" + to_string(num)); - writer.attribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"); - writer.attribute("Target", "sharedStrings.xml"); - writer.end_element(); - num++; - } - - if (!styles.empty()) { - writer.start_element("Relationship"); - writer.attribute("Id", "rId" + to_string(num)); - writer.attribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"); - writer.attribute("Target", "styles.xml"); - writer.end_element(); - } - - writer.end_element(); - - data = move(writer.dump()); - } - - entry = archive_entry_new(); - archive_entry_set_pathname(entry, "xl/_rels/workbook.xml.rels"); - archive_entry_set_size(entry, data.length()); - archive_entry_set_filetype(entry, AE_IFREG); - archive_entry_set_perm(entry, 0644); - archive_write_header(a, entry); - archive_write_data(a, data.data(), data.length()); - // FIXME - set date? - archive_entry_free(entry); -} - -void workbook_pimpl::write_shared_strings(struct archive* a) const { - struct archive_entry* entry; - string data; - - { - xml_writer writer; - - writer.start_document(); - - writer.start_element("sst", {{"", NS_SPREADSHEET}}); - writer.attribute("count", to_string(shared_strings.size())); - writer.attribute("uniqueCount", to_string(shared_strings.size())); - - vector strings; - - strings.resize(shared_strings.size()); - - for (const auto& ss : shared_strings) { - strings[ss.second.num] = ss.first; - } - - for (const auto& s : strings) { - writer.start_element("si"); - - writer.start_element("t"); - writer.attribute("xml:space", "preserve"); - writer.text(s); - writer.end_element(); - - writer.end_element(); - } - - writer.end_element(); - - data = move(writer.dump()); - } - - entry = archive_entry_new(); - archive_entry_set_pathname(entry, "xl/sharedStrings.xml"); - archive_entry_set_size(entry, data.length()); - archive_entry_set_filetype(entry, AE_IFREG); - archive_entry_set_perm(entry, 0644); - archive_write_header(a, entry); - archive_write_data(a, data.data(), data.length()); - // FIXME - set date? - archive_entry_free(entry); -} - -void workbook_pimpl::write_styles(struct archive* a) const { - struct archive_entry* entry; - string data; - - { - xml_writer writer; - vector sty; - vector number_format_nums; - unordered_map number_formats; - vector number_formats2; - font default_font("Arial", 10, false); - unordered_map fonts; - vector fonts2; - - writer.start_document(); - - writer.start_element("styleSheet"); - writer.attribute("xmlns", NS_SPREADSHEET); - - fonts[default_font] = 0; - fonts2.emplace_back(&default_font); - - for (const auto& s : styles) { - if (number_formats.find(s.number_format) == number_formats.end()) { - number_formats[s.number_format] = (unsigned int)number_formats.size(); - number_formats2.emplace_back(&s.number_format); - } - - if (fonts.find(s.font) == fonts.end()) { - fonts[s.font] = (unsigned int)fonts.size(); - fonts2.emplace_back(&s.font); - } - } - - writer.start_element("numFmts"); - writer.attribute("count", to_string(number_formats.size())); - - for (unsigned int i = 0; i < number_formats.size(); i++) { - writer.start_element("numFmt"); - writer.attribute("numFmtId", to_string(i + NUMFMT_OFFSET)); - writer.attribute("formatCode", *number_formats2[i]); - writer.end_element(); - } - - writer.end_element(); - - writer.start_element("fonts"); - writer.attribute("count", to_string(fonts.size())); - - for (unsigned int i = 0; i < fonts.size(); i++) { - writer.start_element("font"); - - if (fonts2[i]->bold) { - writer.start_element("b"); - writer.attribute("val", "true"); - writer.end_element(); - } - - writer.start_element("sz"); - writer.attribute("val", to_string(fonts2[i]->font_size)); - writer.end_element(); - - writer.start_element("name"); - writer.attribute("val", fonts2[i]->font_name); - writer.end_element(); - - writer.end_element(); - } - - writer.end_element(); - - writer.start_element("fills"); - writer.attribute("count", "2"); - - writer.start_element("fill"); - writer.start_element("patternFill"); - writer.attribute("patternType", "none"); - writer.end_element(); - writer.end_element(); - - writer.start_element("fill"); - writer.start_element("patternFill"); - writer.attribute("patternType", "gray125"); - writer.end_element(); - writer.end_element(); - - writer.end_element(); - - writer.start_element("borders"); - writer.attribute("count", "1"); - - writer.start_element("border"); - writer.start_element("left"); writer.end_element(); - writer.start_element("right"); writer.end_element(); - writer.start_element("top"); writer.end_element(); - writer.start_element("bottom"); writer.end_element(); - writer.start_element("diagonal"); writer.end_element(); - writer.end_element(); - - writer.end_element(); - - sty.resize(styles.size()); - - for (const auto& s : styles) { - sty[s.num] = &s; - } - - { - unsigned int style_id = 0; - - writer.start_element("cellXfs"); - writer.attribute("count", to_string(styles.size())); - - for (const auto& s : sty) { - writer.start_element("xf"); - writer.attribute("numFmtId", to_string(number_formats[s->number_format] + NUMFMT_OFFSET)); - writer.attribute("fontId", to_string(fonts[s->font])); - writer.attribute("fillId", "0"); - writer.attribute("borderId", "0"); - writer.attribute("applyFont", "true"); - writer.attribute("applyNumberFormat", "true"); - writer.end_element(); - - style_id++; - } - - writer.end_element(); - } - - writer.end_element(); - - data = move(writer.dump()); - } - - entry = archive_entry_new(); - archive_entry_set_pathname(entry, "xl/styles.xml"); - archive_entry_set_size(entry, data.length()); - archive_entry_set_filetype(entry, AE_IFREG); - archive_entry_set_perm(entry, 0644); - archive_write_header(a, entry); - archive_write_data(a, data.data(), data.length()); - // FIXME - set date? - archive_entry_free(entry); -} - -void workbook_pimpl::write_archive(struct archive* a) const { - for (const auto& sh : sheets) { - sh.impl->write(a); - } - - write_workbook_xml(a); - write_content_types_xml(a); - write_rels(a); - write_workbook_rels(a); - - if (!shared_strings.empty()) - write_shared_strings(a); - - if (!styles.empty()) - write_styles(a); -} - -void workbook_pimpl::save(const filesystem::path& fn) const { - struct archive* a; - - a = archive_write_new(); - archive_write_set_format_zip(a); - - archive_write_open_filename(a, fn.string().c_str()); - - write_archive(a); - - archive_write_close(a); - archive_write_free(a); -} - -void workbook::save(const filesystem::path& fn) const { - impl->save(fn); -} - -static int archive_dummy_callback(struct archive* a, void* client_data) { - return ARCHIVE_OK; -} - -la_ssize_t workbook_pimpl::write_callback(struct archive* a, const void* buffer, size_t length) const { - buf.append((const char*)buffer, length); - - return length; -} - -string workbook_pimpl::data() const { - buf.clear(); - - archive_write_t a{archive_write_new()}; - - archive_write_set_format_zip(a.get()); - archive_write_set_bytes_in_last_block(a.get(), 1); - - auto ret = archive_write_open(a.get(), (void*)this, archive_dummy_callback, - [](struct archive* a, void* client_data, const void* buffer, size_t length) { - auto wb = (const workbook_pimpl*)client_data; - - return wb->write_callback(a, buffer, length); - }, - archive_dummy_callback); - if (ret != ARCHIVE_OK) - Rcpp::stop("archive_write_open returned {}.", ret); - - write_archive(a.get()); - - archive_write_close(a.get()); - - return buf; -} - -string workbook::data() const { - return impl->data(); -} - -row& sheet_pimpl::add_row() { - return *rows.emplace(rows.end(), *this, rows.size() + 1); -} - -row& sheet::add_row() { - return impl->add_row(); -} - -shared_string workbook_pimpl::get_shared_string(string_view s) { - shared_string ss; - - if (shared_strings.contains(s)) - return shared_strings.find(s)->second; - - ss.num = (unsigned int)shared_strings.size(); - - shared_strings.emplace(s, ss); - - return ss; -} - -template -cell_pimpl::cell_pimpl(row_pimpl& r, unsigned int num, const T& t) : parent(r), num(num), val(t) { - if constexpr (is_same_v) - sty = parent.parent.parent.find_style(style("dd/mm/yy", "Arial", 10)); // FIXME - localization - else if constexpr (is_same_v) - sty = parent.parent.parent.find_style(style("HH:MM:SS", "Arial", 10)); // FIXME - localization - else if constexpr (is_same_v) - sty = parent.parent.parent.find_style(style("dd/mm/yy HH:MM:SS", "Arial", 10)); // FIXME - localization - else - sty = parent.parent.parent.find_style(style("General", "Arial", 10)); -} - -cell_pimpl::cell_pimpl(row_pimpl& r, unsigned int num, string_view t) : cell_pimpl(r, num, r.parent.parent.get_shared_string(t)) { -} - -cell::cell(row_pimpl& r, unsigned int num, int64_t val) { - impl = new cell_pimpl(r, num, val); -} - -cell::cell(row_pimpl& r, unsigned int num, string_view val) { - impl = new cell_pimpl(r, num, val); -} - -cell::cell(row_pimpl& r, unsigned int num, double val) { - impl = new cell_pimpl(r, num, val); -} - -cell::cell(row_pimpl& r, unsigned int num, const chrono::year_month_day& val) { - impl = new cell_pimpl(r, num, val); -} - -cell::cell(row_pimpl& r, unsigned int num, const chrono::seconds& val) { - impl = new cell_pimpl(r, num, val); -} - -cell::cell(row_pimpl& r, unsigned int num, const datetime& val) { - impl = new cell_pimpl(r, num, val); -} - -cell::cell(row_pimpl& r, unsigned int num, const chrono::system_clock::time_point& val) { - impl = new cell_pimpl(r, num, val); -} - -cell::cell(row_pimpl& r, unsigned int num, bool val) { - impl = new cell_pimpl(r, num, val); -} - -cell::cell(row_pimpl& r, unsigned int num, nullptr_t) { - impl = new cell_pimpl(r, num, nullptr); -} - -bool operator==(const font& lhs, const font& rhs) noexcept { - return lhs.font_name == rhs.font_name && - lhs.font_size == rhs.font_size && - ((lhs.bold && rhs.bold) || (!lhs.bold && !rhs.bold)); -} - -bool operator==(const style& lhs, const style& rhs) noexcept { - return lhs.number_format == rhs.number_format && - lhs.font == rhs.font; -} - -void style::set_font(string_view font_name, unsigned int font_size, bool bold) { - this->font = xlcpp::font(font_name, font_size, bold); -} - -void style::set_number_format(string_view fmt) { - number_format = fmt; -} - -void cell_pimpl::set_font(string_view name, unsigned int size, bool bold) { - auto sty2 = *sty; - - sty2.set_font(name, size, bold); - - sty = parent.parent.parent.find_style(sty2); -} - -void cell::set_font(string_view name, unsigned int size, bool bold) { - impl->set_font(name, size, bold); -} - -void cell_pimpl::set_number_format(string_view fmt) { - auto sty2 = *sty; - - sty2.set_number_format(fmt); - - sty = parent.parent.parent.find_style(sty2); -} - -void cell::set_number_format(string_view fmt) { - impl->set_number_format(fmt); -} - -workbook::workbook() { - impl = new workbook_pimpl; - impl->date1904 = false; -} - -static void parse_content_types(string_view ct, unordered_map& files) { - xml_reader r(ct); - unsigned int depth = 0; - unordered_map defs, over; - - while (r.read()) { - unsigned int next_depth; - - if (r.node_type() == xml_node::element && !r.is_empty()) - next_depth = depth + 1; - else if (r.node_type() == xml_node::end_element) - next_depth = depth - 1; - else - next_depth = depth; - - if (r.node_type() == xml_node::element) { - if (depth == 0) { - if (r.local_name() != "Types" || !r.namespace_uri_raw().cmp(NS_CONTENT_TYPES)) { - Rcpp::stop("Root tag was {{{}}}{}, expected {{{}}}Types.", - r.namespace_uri_raw().decode(), r.local_name(), NS_CONTENT_TYPES); - } - } else if (depth == 1) { - if (r.local_name() == "Default" && r.namespace_uri_raw().cmp(NS_CONTENT_TYPES)) { - auto ext = try_decode(r.get_attribute("Extension")); - auto ct = try_decode(r.get_attribute("ContentType")); - - defs[ext] = ct; - } else if (r.local_name() == "Override" && r.namespace_uri_raw().cmp(NS_CONTENT_TYPES)) { - auto part = try_decode(r.get_attribute("PartName")); - auto ct = try_decode(r.get_attribute("ContentType")); - - over[part] = ct; - } - } - } - - depth = next_depth; - } - - for (auto& f : files) { - for (const auto& o : over) { - if (o.first == "/" + f.first) { - f.second.content_type = o.second; - break; - } - } - - if (!f.second.content_type.empty()) - continue; - - auto st = f.first.rfind("."); - string ext = st == string::npos ? "" : f.first.substr(st + 1); - - for (const auto& d : defs) { - if (ext == d.first) { - f.second.content_type = d.second; - break; - } - } - } -} - -static const pair& find_workbook(const unordered_map& files) { - for (const auto& f : files) { - if (f.second.content_type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" || - f.second.content_type == "application/vnd.ms-excel.sheet.macroEnabled.main+xml" || - f.second.content_type == "application/vnd.ms-excel.sheet.binary.macroEnabled.main") { - return f; - } - } - - Rcpp::stop("Could not find workbook file."); -} - -string workbook_pimpl::find_number_format(unsigned int num) { - if (num >= cell_styles.size()) - return ""; - - if (!cell_styles[num].has_value()) - return ""; - - unsigned int numfmtid = cell_styles[num].value(); - - for (const auto& nf : number_formats) { - if (nf.first == numfmtid) - return nf.second; - } - - for (const auto& bs : builtin_styles) { - if ((unsigned int)bs.first == numfmtid) - return bs.second; - } - - return ""; -} - -static constexpr bool __inline is_hex(char c) noexcept { - return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); -} - -static constexpr uint8_t __inline hex_digit(char c) noexcept { - if (c >= '0' && c <= '9') - return (uint8_t)(c - '0'); - else if (c >= 'A' && c <= 'F') - return (uint8_t)(c - 'A' + 0xa); - else if (c >= 'a' && c <= 'f') - return (uint8_t)(c - 'a' + 0xa); - - return 0; -} - -static string decode_escape_sequences(string_view sv) { - bool has_underscore = false; - - if (sv.length() < 7) - return string(sv); - - for (auto c : sv) { - if (c == '_') { - has_underscore = true; - break; - } - } - - if (!has_underscore) - return string(sv); - - string s; - - s.reserve(sv.length()); - - for (unsigned int i = 0; i < sv.length(); i++) { - if (i + 6 < sv.length() && sv[i] == '_' && sv[i+1] == 'x' && is_hex(sv[i+2]) && is_hex(sv[i+3]) && is_hex(sv[i+4]) && is_hex(sv[i+5]) && sv[i+6] == '_') { - auto val = (uint16_t)((hex_digit(sv[i+2]) << 12) | (hex_digit(sv[i+3]) << 8) | (hex_digit(sv[i+4]) << 4) | hex_digit(sv[i+5])); - - if (val < 0x80) - s += (char)val; - else if (val < 0x800) { - char buf[3]; - - buf[0] = (char)(0xc0 | (val >> 6)); - buf[1] = (char)(0x80 | (val & 0x3f)); - buf[2] = 0; - - s += buf; - } else { - char buf[4]; - - buf[0] = (char)(0xe0 | (val >> 12)); - buf[1] = (char)(0x80 | ((val & 0xfc0) >> 6)); - buf[2] = (char)(0x80 | (val & 0x3f)); - buf[3] = 0; - - s += buf; - } - - i += 6; - } else - s += sv[i]; - } - - return s; -} - -static constexpr bool is_valid_date(uint16_t y, uint8_t m, uint8_t d) { - if (y == 0 || m == 0 || d == 0) - return false; - - if (d > 31 || m > 12) - return false; - - if (d == 31 && (m == 4 || m == 6 || m == 9 || m == 11)) - return false; - - if (d == 30 && m == 2) - return false; - - if (d == 29 && m == 2) { - if (y % 4) - return false; - - if (!(y % 100) && y % 400) - return false; - } - - return true; -} - -static constexpr bool __inline is_digit(char c) noexcept { - return c >= '0' && c <= '9'; -} - -static variant parse_iso8601(string_view t) { - if (t.length() >= 10 && is_digit(t[0]) && is_digit(t[1]) && is_digit(t[2]) && is_digit(t[3]) && - t[4] == '-' && is_digit(t[5]) && is_digit(t[6]) && t[7] == '-' && is_digit(t[8]) && - is_digit(t[9])) { - uint16_t y; - uint8_t mon, d; - - from_chars_constexpr(t.data(), t.data() + 4, y); - from_chars_constexpr(t.data() + 5, t.data() + 7, mon); - from_chars_constexpr(t.data() + 8, t.data() + 10, d); - - if (!is_valid_date(y, mon, d)) - Rcpp::stop("Invalid ISO 8601 date \"{}\".", t); - - if (t.length() >= 19 && t[10] == 'T' && is_digit(t[11]) && is_digit(t[12]) && t[13] == ':' && - is_digit(t[14]) && is_digit(t[15]) && t[16] == ':' && is_digit(t[17]) && is_digit(t[18])) { - uint8_t h, mins, s; - - from_chars_constexpr(t.data() + 11, t.data() + 13, h); - from_chars_constexpr(t.data() + 14, t.data() + 16, mins); - from_chars_constexpr(t.data() + 17, t.data() + 19, s); - - if (h >= 24 || mins >= 60 || s >= 60) - Rcpp::stop("Invalid ISO 8601 date \"{}\".", t); - - // FIXME - fractional seconds? - - return datetime(chrono::year{y}, chrono::month{mon}, chrono::day{d}, chrono::hours{h}, chrono::minutes{mins}, chrono::seconds{s}); - } - - return chrono::year_month_day{chrono::year{y}, chrono::month{mon}, chrono::day{d}}; - } else - Rcpp::stop("Failed to parse ISO 8601 date \"{}\".", t); -} - -void workbook_pimpl::load_sheet(string_view name, string_view data, bool visible) { - auto& s = *sheets.emplace(sheets.end(), *this, name, sheets.size() + 1, visible); - - xml_reader r(data); - unsigned int depth = 0; - bool in_sheet_data = false; - unsigned int last_index = 0, last_col = 0; - row* row = nullptr; - string s_val, t_val, v_val, is_val; - bool in_v = false, in_is = false; - - while (r.read()) { - unsigned int next_depth; - - if (r.node_type() == xml_node::element && !r.is_empty()) - next_depth = depth + 1; - else if (r.node_type() == xml_node::end_element) - next_depth = depth - 1; - else - next_depth = depth; - - if (r.node_type() == xml_node::element) { - if (depth == 0) { - if (r.local_name() != "worksheet" || (!r.namespace_uri_raw().cmp(NS_SPREADSHEET) && !r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { - Rcpp::stop("Root tag was {{{}}}{}, expected {{{}}}worksheet.", - r.namespace_uri_raw().decode(), r.local_name(), NS_SPREADSHEET); - } - } else if (depth == 1 && r.local_name() == "sheetData" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT)) && !r.is_empty()) - in_sheet_data = true; - else if (in_sheet_data) { - if (r.local_name() == "row" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { - unsigned int row_index = 0; - auto rsv = r.get_attribute("r"); - - if (rsv) { - auto value = rsv.value().decode(); - auto [ptr, ec] = from_chars(value.data(), value.data() + value.length(), row_index); - - if (ptr != value.data() + value.length()) - Rcpp::stop("Invalid r attribute \"{}\" for row tag.", value); - } - - if (row_index == 0) - Rcpp::stop("No row index given."); - - if (row_index <= last_index) - Rcpp::stop("Rows out of order."); - - while (last_index + 1 < row_index) { - s.impl->rows.emplace(s.impl->rows.end(), *s.impl, s.impl->rows.size() + 1); - last_index++; - } - - s.impl->rows.emplace(s.impl->rows.end(), *s.impl, s.impl->rows.size() + 1); - - row = &s.impl->rows.back(); - - last_index = row_index; - last_col = 0; - } else if (row && r.local_name() == "c" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { - unsigned int row_num, col_num; - auto r_val = try_decode(r.get_attribute("r")); - - v_val = ""; - is_val = ""; - - t_val = try_decode(r.get_attribute("t")); - s_val = try_decode(r.get_attribute("s")); - - if (r_val.empty()) - Rcpp::stop("Cell had no r value."); - - if (!resolve_reference(r_val, row_num, col_num)) - Rcpp::stop("Malformed reference \"{}\".", r_val); - - if (row_num + 1 != last_index) - Rcpp::stop("Cell was in wrong row."); - - if (col_num < last_col) - Rcpp::stop("Cells out of order."); - - while (last_col < col_num) { - row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - last_col++; - } - - last_col = col_num + 1; - - if (r.is_empty()) - row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - } else if (row && r.local_name() == "v" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT)) && !r.is_empty()) - in_v = true; - else if (row && r.local_name() == "is" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT)) && !r.is_empty()) - in_is = true; - } - } else if (r.node_type() == xml_node::end_element) { - if (depth == 1 && r.local_name() == "sheetData" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) - in_sheet_data = false; - else if (depth == 2 && r.local_name() == "row" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) - row = nullptr; - else if (row && r.local_name() == "c" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { - cell* c; - string number_format; - - if (!s_val.empty()) - number_format = find_number_format(stoi(s_val)); - - if (t_val == "n" || t_val.empty()) { // number - bool dt = is_date(number_format); - bool tm = is_time(number_format); - - // FIXME - we can optimize is_date and is_time if one of the preset number formats - - if (dt && tm) { - auto d = stod(v_val); - auto n = (unsigned int)((d - (int)d) * 86400.0); - datetime dt(1970y, chrono::January, 1d, chrono::seconds{n}); - - dt.d = number_to_date((int)d, date1904); - - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, dt); - } else if (dt) { - int num; - - auto [ptr, ec] = from_chars(v_val.data(), v_val.data() + v_val.length(), num); - - if (ec == errc() && ptr == v_val.data() + v_val.length()) { - auto ymd = number_to_date(num, date1904); - - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, ymd); - } else - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - } else if (tm) { - auto n = (unsigned int)(stod(v_val) * 86400.0); - - chrono::seconds t{n % 86400}; - - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, t); - } else { - bool is_int = true; - - for (const auto c : v_val) { - if (c != '-' && (c < '0' || c > '9')) { - is_int = false; - break; - } - } - - if (is_int) { - int64_t val; - - auto [ptr, ec] = from_chars(v_val.data(), v_val.data() + v_val.length(), val); - - if (ptr != v_val.data() + v_val.length()) - Rcpp::stop("Could not convert {} to int64_t.", v_val); - - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, val); - } else - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, stod(v_val)); - } - } else if (t_val == "b") // boolean - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, stoi(v_val) != 0); - else if (t_val == "s") { // shared string - shared_string ss; - - auto [ptr, ec] = from_chars(v_val.data(), v_val.data() + v_val.length(), ss.num); - - if (ptr != v_val.data() + v_val.length()) - Rcpp::stop("Invalid v attribute \"{}\" on shared-string cell.", v_val); - - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - - // so we don't have to expose shared_string publicly - delete c->impl; - c->impl = new cell_pimpl(*row->impl, (unsigned int)row->impl->cells.size(), ss); - } else if (t_val == "e") // error - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - else if (t_val == "str") { // string - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - - if (!v_val.empty()) { - // so we don't have to expose shared_string publicly - c->impl->val = decode_escape_sequences(v_val); - } - } else if (t_val == "inlineStr") { // inline string - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - - if (!is_val.empty()) { - // so we don't have to expose shared_string publicly - c->impl->val = decode_escape_sequences(is_val); - } - } else if (t_val == "d") { // datetime - auto dt = parse_iso8601(v_val); - - visit([&](auto&& arg) { - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, arg); - }, dt); - } else - Rcpp::stop("Unhandled cell type value \"{}\".", t_val); - - if (!s_val.empty()) - c->impl->number_format = number_format; - } else if (in_v && r.local_name() == "v" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) - in_v = false; - else if (in_is && r.local_name() == "is" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) - in_is = false; - } else if (r.node_type() == xml_node::text) { - if (in_v) - v_val += r.value(); - else if (in_is) - is_val += r.value(); - } - - depth = next_depth; - } -} - -void workbook_pimpl::parse_workbook(string_view fn, string_view data, const unordered_map& files) { - xml_reader r(data); - unsigned int depth = 0; - - struct sheet_info { - sheet_info(string_view rid, string_view name, bool visible) : - rid(rid), name(name), visible(visible) { } - - string rid; - string name; - bool visible; - }; - - vector sheets_rels; - - while (r.read()) { - unsigned int next_depth; - - if (r.node_type() == xml_node::element && !r.is_empty()) - next_depth = depth + 1; - else if (r.node_type() == xml_node::end_element) - next_depth = depth - 1; - else - next_depth = depth; - - if (r.node_type() == xml_node::element) { - if (depth == 0) { - if (r.local_name() != "workbook" || (!r.namespace_uri_raw().cmp(NS_SPREADSHEET) && !r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { - Rcpp::stop("Root tag was {{{}}}{}, expected {{{}}}workbook.", - r.namespace_uri_raw().decode(), r.local_name(), NS_SPREADSHEET); - } - } else if (depth == 1) { - if (r.local_name() == "workbookPr" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { - auto date1904sv = r.get_attribute("date1904"); - - if (date1904sv) { - auto value = date1904sv.value().decode(); - date1904 = value == "true" || value == "1"; - } - } - } else if (depth == 2) { - if (r.local_name() == "sheet" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { - bool visible = true; - - auto sheet_name = try_decode(r.get_attribute("name")); - string rid; - - if (r.get_attribute("id", NS_RELATIONSHIPS).has_value()) - rid = r.get_attribute("id", NS_RELATIONSHIPS).value().decode(); - else if (r.get_attribute("id", NS_RELATIONSHIPS_STRICT).has_value()) - rid = r.get_attribute("id", NS_RELATIONSHIPS_STRICT).value().decode(); - - if (!rid.empty()) { - auto statesv = r.get_attribute("state"); - if (statesv) - visible = statesv.value().decode() != "hidden"; - - if (!sheet_name.empty()) - sheets_rels.emplace_back(rid, sheet_name, visible); - } - } - } - } - - depth = next_depth; - } - - // FIXME - preserve sheet order - - auto rels = read_relationships(fn, files); - - for (const auto& sr : sheets_rels) { - for (const auto& r : rels) { - if (r.first == sr.rid) { - auto name = filesystem::path(fn); - - // FIXME - can we resolve relative paths properly? - - name.remove_filename(); - name /= r.second; - - auto ns = name.string(); - - for (auto& c : ns) { - if (c == '\\') - c = '/'; - } - - if (files.count(ns) == 0) - Rcpp::stop("File {} not found.", ns); - - load_sheet(sr.name, files.at(ns).data, sr.visible); - break; - } - } - } -} - -void workbook_pimpl::load_shared_strings2(string_view sv) { - xml_reader r(sv); - unsigned int depth = 0; - bool in_si = false; - string si_val; - - while (r.read()) { - unsigned int next_depth; - - if (r.node_type() == xml_node::element && !r.is_empty()) - next_depth = depth + 1; - else if (r.node_type() == xml_node::end_element) - next_depth = depth - 1; - else - next_depth = depth; - - if (r.node_type() == xml_node::element) { - if (depth == 0) { - if (r.local_name() != "sst" || (!r.namespace_uri_raw().cmp(NS_SPREADSHEET) && !r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { - Rcpp::stop("Root tag was {{{}}}{}, expected {{{}}}sst.", - r.namespace_uri_raw().decode(), r.local_name(), NS_SPREADSHEET); - } - } else if (depth == 1) { - if (r.local_name() == "si" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { - in_si = true; - si_val = ""; - } - } - } else if (r.node_type() == xml_node::text) { - if (in_si) - si_val += decode_escape_sequences(r.value()); - } else if (r.node_type() == xml_node::end_element) { - if (r.local_name() == "si" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { - shared_strings2.emplace_back(si_val); - in_si = false; - } - } - - depth = next_depth; - } -} - -void workbook_pimpl::load_shared_strings(const unordered_map& files) { - for (const auto& f : files) { - if (f.second.content_type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml") { - load_shared_strings2(f.second.data); - return; - } else if (f.second.content_type == "application/vnd.ms-excel.sharedStrings") { - load_shared_strings_binary(span((uint8_t*)f.second.data.data(), f.second.data.size())); - return; - } - } -} - -void workbook_pimpl::load_styles2(string_view sv) { - xml_reader r(sv); - unsigned int depth = 0; - bool in_numfmts = false, in_cellxfs = false; - - while (r.read()) { - unsigned int next_depth; - - if (r.node_type() == xml_node::element && !r.is_empty()) - next_depth = depth + 1; - else if (r.node_type() == xml_node::end_element) - next_depth = depth - 1; - else - next_depth = depth; - - if (r.node_type() == xml_node::element) { - if (depth == 0) { - if (r.local_name() != "styleSheet" || (!r.namespace_uri_raw().cmp(NS_SPREADSHEET) && !r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { - Rcpp::stop("Root tag was {{{}}}{}, expected {{{}}}styleSheet.", - r.namespace_uri_raw().decode(), r.local_name(), NS_SPREADSHEET); - } - } else if (depth == 1) { - if (r.local_name() == "numFmts" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT)) && !r.is_empty()) - in_numfmts = true; - else if (r.local_name() == "cellXfs" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT)) && !r.is_empty()) - in_cellxfs = true; - } else if (depth == 2) { - if (in_numfmts && r.local_name() == "numFmt" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { - unsigned int id = 0; - string format_code; - - auto numfmtsv = r.get_attribute("numFmtId"); - if (numfmtsv) { - auto value = numfmtsv.value().decode(); - auto fcr = from_chars(value.data(), value.data() + value.length(), id); - - if (fcr.ec != errc() || fcr.ptr != value.data() + value.length()) - Rcpp::stop("Failed to parse numFmtId value {}.", value); - - if (id != 0) - number_formats[id] = try_decode(r.get_attribute("formatCode")); - } - } else if (in_cellxfs && r.local_name() == "xf" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) { - optional numfmtid; - bool apply_number_format = true; - - auto numfmtsv = r.get_attribute("numFmtId"); - if (numfmtsv) { - unsigned int num; - - auto value = numfmtsv.value().decode(); - auto fcr = from_chars(value.data(), value.data() + value.length(), num); - - if (fcr.ec != errc() || fcr.ptr != value.data() + value.length()) - Rcpp::stop("Failed to parse numFmtId value {}.", value); - - numfmtid = num; - } - - auto applysv = r.get_attribute("applyNumberFormat"); - if (applysv) { - auto value = applysv.value().decode(); - apply_number_format = value == "true" || value == "1"; - } - - if (!apply_number_format) - numfmtid = nullopt; - - cell_styles.push_back(numfmtid); - } - } - } else if (r.node_type() == xml_node::end_element) { - if (in_numfmts && r.local_name() == "numFmts" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) - in_numfmts = false; - else if (in_cellxfs && r.local_name() == "cellXfs" && (r.namespace_uri_raw().cmp(NS_SPREADSHEET) || r.namespace_uri_raw().cmp(NS_SPREADSHEET_STRICT))) - in_cellxfs = false; - } - - depth = next_depth; - } -} - -void workbook_pimpl::load_styles(const unordered_map& files) { - for (const auto& f : files) { - if (f.second.content_type == "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml") { - load_styles2(f.second.data); - return; - } else if (f.second.content_type == "application/vnd.ms-excel.styles") { - load_styles_binary(span((uint8_t*)f.second.data.data(), f.second.data.size())); - return; - } - } -} +namespace xlcpp { +/* needed??? */ #ifdef _WIN32 __inline string utf16_to_utf8(const u16string_view& s) { string ret; @@ -1754,59 +69,6 @@ __inline string utf16_to_utf8(const u16string_view& s) { } #endif -void workbook_pimpl::load_archive(struct archive* a) { - struct archive_entry* entry; - unordered_map files; - - while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { - if (archive_entry_filetype(entry) == AE_IFREG && archive_entry_pathname(entry)) { - filesystem::path name = archive_entry_pathname(entry); - auto ext = name.extension().string(); - - for (auto& c : ext) { - if (c >= 'A' && c <= 'Z') - c = c - 'A' + 'a'; - } - - if (ext != ".xml" && ext != ".rels" && ext != ".bin") - continue; - - string buf; - string tmp(BLOCK_SIZE, 0); - - do { - auto read = archive_read_data(a, tmp.data(), BLOCK_SIZE); - - if (read == 0) - break; - - if (read < 0) - Rcpp::stop("archive_read_data returned {} for {} ({})", read, name.string(), archive_error_string(a)); - - buf += tmp.substr(0, read); - } while (true); - - files[name.string()].data = buf; - } - } - - if (files.count("[Content_Types].xml") == 0) - Rcpp::stop("[Content_Types].xml not found."); - - parse_content_types(files.at("[Content_Types].xml").data, files); - - load_shared_strings(files); - - load_styles(files); - - auto& wb = find_workbook(files); - - if (wb.second.content_type == "application/vnd.ms-excel.sheet.binary.macroEnabled.main") - parse_workbook_binary(wb.first, span((uint8_t*)wb.second.data.data(), wb.second.data.size()), files); - else - parse_workbook(wb.first, wb.second.data, files); -} - workbook_pimpl::workbook_pimpl(const filesystem::path& fn, string_view password, string_view outfile) { #ifdef _WIN32 unique_handle hup{CreateFileW((LPCWSTR)fn.u16string().c_str(), FILE_READ_DATA | DELETE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, @@ -1878,24 +140,6 @@ void workbook_pimpl::load_from_memory(span mem, string_view passw mem = plaintext; } - archive_read_t a{archive_read_new()}; - - archive_read_support_format_zip(a.get()); - - auto r = archive_read_open_memory(a.get(), mem.data(), mem.size()); - - if (r != ARCHIVE_OK) - Rcpp::stop("{}", archive_error_string(a.get())); - - // archive_read_t b{archive_read_new()}; - // archive_write_set_format_zip(b.get()); - // archive_write_open_filename(b.get(), "/tmp/test.xlsx"); - // // archive_write_data_block(b, mem.data(), mem.size(), 0); - // // archive_write_data(b, mem.data(), mem.size()); - // archive_write_open_memory(b, mem.data(), mem.size()); - // archive_write_close(b.get()); - // archive_write_free(b.get()); - // FIXME I'm to stupid to write the file with libarchive if (outfile.compare("") != 0) { @@ -1903,8 +147,6 @@ void workbook_pimpl::load_from_memory(span mem, string_view passw xlsx.write((char *) mem.data(), mem.size()); xlsx.close(); } - - load_archive(a.get()); } workbook::workbook(const filesystem::path& fn, std::string_view password, std::string_view outfile) { @@ -1919,152 +161,4 @@ workbook::~workbook() { delete impl; } -sheet::sheet(workbook_pimpl& wb, string_view name, unsigned int num, bool visible) { - impl = new sheet_pimpl(wb, name, num, visible); -} - -sheet::~sheet() { - delete impl; -} - -row::row(sheet_pimpl& s, unsigned int num) { - impl = new row_pimpl(s, num); -} - -row::~row() { - delete impl; -} - -cell& row::add_cell(int64_t val) { - return impl->add_cell(val); -} - -cell& row::add_cell(string_view val) { - return impl->add_cell(val); -} - -cell& row::add_cell(double val) { - return impl->add_cell(val); -} - -cell& row::add_cell(const chrono::year_month_day& val) { - return impl->add_cell(val); -} - -cell& row::add_cell(const chrono::seconds& val) { - return impl->add_cell(val); -} - -cell& row::add_cell(const datetime& val) { - return impl->add_cell(val); -} - -cell& row::add_cell(const chrono::system_clock::time_point& val) { - return impl->add_cell(val); -} - -cell& row::add_cell(bool val) { - return impl->add_cell(val); -} - -cell& row::add_cell(nullptr_t) { - return impl->add_cell(nullptr); -} - -const list& workbook::sheets() const { - return impl->sheets; -} - -string sheet::name() const { - return impl->name; -} - -bool sheet::visible() const { - return impl->visible; -} - -const list& sheet::rows() const { - return impl->rows; -} - -const list& row::cells() const { - return impl->cells; -} - -ostream& operator<<(ostream& os, const cell& c) { - visit([&](auto&& arg) { - using T = decay_t; - - if constexpr (is_same_v) - os << arg; - else if constexpr (is_same_v) - os << arg; - else if constexpr (is_same_v) - os << (arg ? "true" : "false"); - else if constexpr (is_same_v) - os << c.impl->parent.parent.parent.shared_strings2[arg.num]; - else if constexpr (is_same_v) - os << fmt::format("{:04}-{:02}-{:02}", (int)arg.year(), (unsigned int)arg.month(), (unsigned int)arg.day()); - else if constexpr (is_same_v) { - const auto& t = chrono::hh_mm_ss{arg}; - - os << fmt::format("{:02}:{:02}:{:02}", t.hours().count(), t.minutes().count(), t.seconds().count()); - } else if constexpr (is_same_v) { - const auto& t = chrono::hh_mm_ss{arg.t}; - - os << fmt::format("{:04}-{:02}-{:02} {:02}:{:02}:{:02}", - (int)arg.d.year(), (unsigned int)arg.d.month(), (unsigned int)arg.d.day(), - t.hours().count(), t.minutes().count(), t.seconds().count()); - } else if constexpr (is_same_v) { - // nop - } else if constexpr (is_same_v) - os << arg; - else - static_assert(always_false_v); - }, c.impl->val); - - return os; -} - -string cell::get_number_format() const { - return impl->number_format; -} - -cell_t cell::value() const { - decltype(value()) v; - - visit([&](auto&& arg) { - if constexpr (is_same_v, shared_string>) - v = impl->parent.parent.parent.shared_strings2[get(impl->val).num]; - else - v = arg; - }, impl->val); - - return v; -} - -#ifdef _WIN32 -void workbook_pimpl::rename(const filesystem::path& fn) const { - vector buf; - auto dest = fn.u16string(); - - buf.resize(offsetof(FILE_RENAME_INFO, FileName) + ((dest.length() + 1) * sizeof(char16_t))); - - auto fri = (FILE_RENAME_INFO*)buf.data(); - - fri->ReplaceIfExists = true; - fri->RootDirectory = nullptr; - fri->FileNameLength = (DWORD)(dest.length() * sizeof(char16_t)); - memcpy(fri->FileName, dest.data(), fri->FileNameLength); - fri->FileName[dest.length()] = 0; - - if (!SetFileInformationByHandle(h.get(), FileRenameInfo, fri, (DWORD)buf.size())) - throw last_error("SetFileInformationByHandle", GetLastError()); -} - -void workbook::rename(const filesystem::path& fn) const { - impl->rename(fn); -} -#endif - } diff --git a/src/xlcpp/xlcpp.h b/src/xlcpp/xlcpp.h index fac2fcaed..49c2b84a9 100644 --- a/src/xlcpp/xlcpp.h +++ b/src/xlcpp/xlcpp.h @@ -7,19 +7,19 @@ #include #include -#ifdef _WIN32 - -#include - -#ifdef XLCPP_EXPORT -#define XLCPP __declspec(dllexport) -#elif !defined(XLCPP_STATIC) -#define XLCPP __declspec(dllimport) -#else -#define XLCPP -#endif - -#else +// #ifdef _WIN32 +// +// #include +// +// #ifdef XLCPP_EXPORT +// #define XLCPP __declspec(dllexport) +// #elif !defined(XLCPP_STATIC) +// #define XLCPP __declspec(dllimport) +// #else +// #define XLCPP +// #endif +// +// #else #ifdef XLCPP_EXPORT #define XLCPP __attribute__ ((visibility ("default"))) @@ -29,7 +29,7 @@ #define XLCPP #endif -#endif +// #endif namespace xlcpp { @@ -42,114 +42,9 @@ class XLCPP workbook { workbook(const std::filesystem::path& fn, std::string_view password = "", std::string_view outfile = ""); workbook(std::span sv, std::string_view password = "", std::string_view outfile = ""); ~workbook(); - sheet& add_sheet(std::string_view name, bool visible = true); - void save(const std::filesystem::path& fn) const; - std::string data() const; - const std::list& sheets() const; -#ifdef _WIN32 - void rename(const std::filesystem::path& fn) const; -#endif workbook_pimpl* impl; }; -class sheet_pimpl; -class row; - -class XLCPP sheet { -public: - sheet(workbook_pimpl& wb, std::string_view name, unsigned int num, bool visible = true); - ~sheet(); - row& add_row(); - std::string name() const; - bool visible() const; - const std::list& rows() const; - - sheet_pimpl* impl; -}; - -class XLCPP datetime { -public: - constexpr datetime(std::chrono::year year, std::chrono::month month, std::chrono::day day, std::chrono::hours hour, std::chrono::minutes minute, std::chrono::seconds second) : - d(year, month, day), t(hour + minute + second) { } - constexpr datetime(std::chrono::year year, std::chrono::month month, std::chrono::day day, std::chrono::seconds t) : - d(year, month, day), t(t) { } - - template - constexpr datetime(const std::chrono::time_point& chr) : - d(std::chrono::floor(chr)), - t(std::chrono::floor(chr - std::chrono::floor(chr)).count()) { - } - - std::chrono::year_month_day d; - std::chrono::seconds t; -}; - -class row_pimpl; -class cell_pimpl; - -using cell_t = std::variant; - -class XLCPP cell { -public: - cell(row_pimpl& r, unsigned int num, std::nullptr_t); - cell(row_pimpl& r, unsigned int num, int64_t val); - cell(row_pimpl& r, unsigned int num, std::string_view val); - cell(row_pimpl& r, unsigned int num, double val); - cell(row_pimpl& r, unsigned int num, const std::chrono::year_month_day& val); - cell(row_pimpl& r, unsigned int num, const std::chrono::seconds& val); - cell(row_pimpl& r, unsigned int num, const datetime& val); - cell(row_pimpl& r, unsigned int num, const std::chrono::system_clock::time_point& val); - cell(row_pimpl& r, unsigned int num, bool val); - - template - cell(row_pimpl& r, unsigned int num, T* t) = delete; - - void set_number_format(std::string_view fmt); - void set_font(std::string_view name, unsigned int size, bool bold = false); - std::string get_number_format() const; - cell_t value() const; - - cell_pimpl* impl; -}; - -XLCPP std::ostream& operator<<(std::ostream& os, const cell& c); - -class XLCPP row { -public: - row(sheet_pimpl& s, unsigned int num); - ~row(); - - cell& add_cell(int64_t val); - cell& add_cell(std::string_view val); - cell& add_cell(double val); - cell& add_cell(const std::chrono::year_month_day& val); - cell& add_cell(const std::chrono::seconds& val); - cell& add_cell(const datetime& val); - cell& add_cell(const std::chrono::system_clock::time_point& val); - cell& add_cell(bool val); - cell& add_cell(std::nullptr_t); - - cell& add_cell(const char* val) { - return add_cell(std::string_view(val)); - } - - cell& add_cell(char* val) { - return add_cell(std::string_view(val)); - } - - template - requires std::is_integral_v - cell& add_cell(T val) { - return add_cell(static_cast(val)); - } - - template - cell& add_cell(T* val) = delete; - - const std::list& cells() const; - - row_pimpl* impl; -}; }; diff --git a/src/xlcpp/xlsb.cpp b/src/xlcpp/xlsb.cpp deleted file mode 100644 index 8bc1e9ea6..000000000 --- a/src/xlcpp/xlsb.cpp +++ /dev/null @@ -1,565 +0,0 @@ -#include "openxlsx2.h" - -#include "xlcpp.h" -#include "xlcpp-pimpl.h" -#include "cfbf.h" -#include "utf16.h" -#include "xlsb.h" - -using namespace std; - -namespace xlcpp { - -static void xlsb_walk(span data, const function)>& func) { - while (!data.empty()) { - uint16_t type; - uint32_t length; - - type = data[0]; - data = data.subspan(1); - - if (type & 0x80) { - type = (uint16_t)((type & 0x7f) | ((uint16_t)data[0] << 7)); - data = data.subspan(1); - } - - length = data[0]; - data = data.subspan(1); - - if (length & 0x80) { - length = (length & 0x7f) | ((uint32_t)data[0] << 7); - data = data.subspan(1); - } - - if (length & 0x4000) { - length = (length & 0x3fff) | ((uint32_t)data[0] << 14); - data = data.subspan(1); - } - - if (length & 0x200000) { - length = (length & 0x1fffff) | ((uint32_t)(data[0] & 0x7f) << 21); - data = data.subspan(1); - } - - func((enum xlsb_type)type, data.subspan(0, length)); - - data = data.subspan(length); - } -} - -void workbook_pimpl::load_sheet_binary(string_view name, span data, bool visible) { - auto& s = *sheets.emplace(sheets.end(), *this, name, sheets.size() + 1, visible); - unsigned int last_index = 0, last_col = 0; - row* row = nullptr; - bool in_sheet_data = false; - - xlsb_walk(data, [&](enum xlsb_type type, span d) { - switch (type) { - case xlsb_type::BrtBeginSheetData: - in_sheet_data = true; - break; - - case xlsb_type::BrtEndSheetData: - in_sheet_data = false; - break; - - case xlsb_type::BrtRowHdr: { - if (!in_sheet_data) - break; - - if (d.size() < sizeof(brt_row_hdr)) - Rcpp::stop("Malformed BrtRowHdr record."); - - const auto& h = *(brt_row_hdr*)d.data(); - - if (h.rw < last_index) - Rcpp::stop("Rows out of order."); - - while (last_index < h.rw) { - s.impl->rows.emplace(s.impl->rows.end(), *s.impl, s.impl->rows.size() + 1); - last_index++; - } - - s.impl->rows.emplace(s.impl->rows.end(), *s.impl, s.impl->rows.size() + 1); - - row = &s.impl->rows.back(); - - last_index = h.rw + 1; - last_col = 0; - - break; - } - - case xlsb_type::BrtCellBlank: - case xlsb_type::BrtCellError: - case xlsb_type::BrtFmlaError: { - if (!in_sheet_data) - break; - - if (d.size() < sizeof(xlsb_cell)) - Rcpp::stop("Malformed cell record."); - - const auto& h = *(xlsb_cell*)d.data(); - - if (h.column < last_col) - Rcpp::stop("Cells out of order."); - - while (last_col < h.column) { - row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - last_col++; - } - - last_col = h.column + 1; - - auto number_format = find_number_format(h.iStyleRef); - - row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - break; - } - - case xlsb_type::BrtCellRk: { - if (!in_sheet_data) - break; - - if (d.size() < sizeof(brt_cell_rk)) - Rcpp::stop("Malformed BrtCellRk record."); - - const auto& h = *(brt_cell_rk*)d.data(); - - if (h.cell.column < last_col) - Rcpp::stop("Cells out of order."); - - while (last_col < h.cell.column) { - row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - last_col++; - } - - last_col = h.cell.column + 1; - - auto number_format = find_number_format(h.cell.iStyleRef); - - double d; - - if (h.value.fInt) { - auto num = h.value.num; - auto val = *reinterpret_cast(&num); - - d = val; - } else { - auto num = ((uint64_t)h.value.num) << 34; - d = *reinterpret_cast(&num); - } - - if (h.value.fx100) - d /= 100.0; - - bool dt = is_date(number_format); - bool tm = is_time(number_format); - cell* c; - - // FIXME - we can optimize is_date and is_time if one of the preset number formats - - if (dt && tm) { - auto n = (unsigned int)((d - (int)d) * 86400.0); - datetime dt(1970y, chrono::January, 1d, chrono::seconds{n}); - - dt.d = number_to_date((int)d, date1904); - - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, dt); - } else if (dt) { - auto ymd = number_to_date((unsigned int)d, date1904); - - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, ymd); - } else if (tm) { - auto n = (unsigned int)(d * 86400.0); - chrono::seconds t{n % 86400}; - - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, t); - } else - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, d); - - c->impl->number_format = number_format; - - break; - } - - case xlsb_type::BrtCellBool: - case xlsb_type::BrtFmlaBool: { - if (!in_sheet_data) - break; - - if (d.size() < sizeof(brt_cell_bool)) - Rcpp::stop("Malformed BrtCellBool record."); - - const auto& h = *(brt_cell_bool*)d.data(); - - if (h.cell.column < last_col) - Rcpp::stop("Cells out of order."); - - while (last_col < h.cell.column) { - row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - last_col++; - } - - last_col = h.cell.column + 1; - - auto number_format = find_number_format(h.cell.iStyleRef); - - auto c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, h.fBool != 0); - - c->impl->number_format = number_format; - - break; - } - - case xlsb_type::BrtCellReal: - case xlsb_type::BrtFmlaNum: { - if (!in_sheet_data) - break; - - if (d.size() < sizeof(brt_cell_real)) - Rcpp::stop("Malformed BrtCellReal record."); - - const auto& h = *(brt_cell_real*)d.data(); - - if (h.cell.column < last_col) - Rcpp::stop("Cells out of order."); - - while (last_col < h.cell.column) { - row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - last_col++; - } - - last_col = h.cell.column + 1; - - auto number_format = find_number_format(h.cell.iStyleRef); - - bool dt = is_date(number_format); - bool tm = is_time(number_format); - cell* c; - - if (dt && tm) { - auto n = (unsigned int)((h.xnum - (int)h.xnum) * 86400.0); - datetime dt(1970y, chrono::January, 1d, chrono::seconds{n}); - - dt.d = number_to_date((int)h.xnum, date1904); - - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, dt); - } else if (dt) { - auto ymd = number_to_date((unsigned int)h.xnum, date1904); - - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, ymd); - } else if (tm) { - auto n = (unsigned int)(h.xnum * 86400.0); - chrono::seconds t{n % 86400}; - - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, t); - } else - c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, h.xnum); - - c->impl->number_format = number_format; - - break; - } - - case xlsb_type::BrtCellSt: - case xlsb_type::BrtFmlaString: { - if (!in_sheet_data) - break; - - if (d.size() < offsetof(brt_cell_st, str)) - Rcpp::stop("Malformed BrtCellSt record."); - - const auto& h = *(brt_cell_st*)d.data(); - - if (d.size() < offsetof(brt_cell_st, str) + (h.len * sizeof(char16_t))) - Rcpp::stop("Malformed BrtCellSt record."); - - if (h.cell.column < last_col) - Rcpp::stop("Cells out of order."); - - while (last_col < h.cell.column) { - row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - last_col++; - } - - last_col = h.cell.column + 1; - - auto number_format = find_number_format(h.cell.iStyleRef); - - auto u16sv = u16string_view(h.str, h.len); - - auto c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - - // so we don't have to expose shared_string publicly - c->impl->val = utf16_to_utf8(u16sv); - c->impl->number_format = number_format; - - break; - } - - case xlsb_type::BrtCellIsst: { - if (!in_sheet_data) - break; - - if (d.size() < sizeof(brt_cell_isst)) - Rcpp::stop("Malformed BrtCellIsst record."); - - const auto& h = *(brt_cell_isst*)d.data(); - - if (h.cell.column < last_col) - Rcpp::stop("Cells out of order."); - - while (last_col < h.cell.column) { - row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - last_col++; - } - - last_col = h.cell.column + 1; - - auto number_format = find_number_format(h.cell.iStyleRef); - - shared_string ss; - ss.num = h.isst; - - auto c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - - // so we don't have to expose shared_string publicly - delete c->impl; - c->impl = new cell_pimpl(*row->impl, (unsigned int)row->impl->cells.size(), ss); - - c->impl->number_format = number_format; - - break; - } - - case xlsb_type::BrtCellRString: { - if (!in_sheet_data) - break; - - if (d.size() < offsetof(brt_cell_rstring, value.str)) - Rcpp::stop("Malformed BrtCellRString record."); - - const auto& h = *(brt_cell_rstring*)d.data(); - - if (d.size() < offsetof(brt_cell_rstring, value.str) + (h.value.len * sizeof(char16_t))) - Rcpp::stop("Malformed BrtCellRString record."); - - if (h.cell.column < last_col) - Rcpp::stop("Cells out of order."); - - while (last_col < h.cell.column) { - row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - last_col++; - } - - last_col = h.cell.column + 1; - - auto number_format = find_number_format(h.cell.iStyleRef); - - auto u16sv = u16string_view(h.value.str, h.value.len); - - auto c = &*row->impl->cells.emplace(row->impl->cells.end(), *row->impl, row->impl->cells.size() + 1, nullptr); - - // so we don't have to expose shared_string publicly - c->impl->val = utf16_to_utf8(u16sv); - - c->impl->number_format = number_format; - - break; - } - - default: - break; - } - }); -} - -void workbook_pimpl::parse_workbook_binary(string_view fn, span data, const unordered_map& files) { - struct sheet_info { - sheet_info(string_view rid, string_view name, bool visible) : - rid(rid), name(name), visible(visible) { } - - string rid; - string name; - bool visible; - }; - - vector sheets_rels; - - xlsb_walk(data, [&](enum xlsb_type type, span d) { - switch (type) { - case xlsb_type::BrtBundleSh: { - if (d.size() < sizeof(brt_bundle_sh)) - Rcpp::stop("Malformed BrtBundleSh entry."); - - auto& h = *(brt_bundle_sh*)d.data(); - - d = d.subspan(sizeof(brt_bundle_sh)); - - if (d.size() < sizeof(uint32_t)) - Rcpp::stop("Malformed BrtBundleSh entry."); - - auto relid_size = *(uint32_t*)d.data(); - - d = d.subspan(sizeof(uint32_t)); - - if (relid_size == 0xffffffff) - relid_size = 0; - - if (d.size() < relid_size * sizeof(char16_t)) - Rcpp::stop("Malformed BrtBundleSh entry."); - - auto strRelID = u16string_view((char16_t*)d.data(), relid_size); - - d = d.subspan(relid_size * sizeof(char16_t)); - - if (d.size() < sizeof(uint32_t)) - Rcpp::stop("Malformed BrtBundleSh entry."); - - auto name_size = *(uint32_t*)d.data(); - - d = d.subspan(sizeof(uint32_t)); - - if (d.size() < name_size * sizeof(char16_t)) - Rcpp::stop("Malformed BrtBundleSh entry."); - - auto strName = u16string_view((char16_t*)d.data(), name_size); - - sheets_rels.emplace_back(utf16_to_utf8(strRelID), utf16_to_utf8(strName), h.hsState == 0); - - break; - } - - case xlsb_type::BrtWbProp: { - if (d.size() < sizeof(brt_wb_prop)) - Rcpp::stop("Malformed BrtWbProp entry."); - - const auto& h = *(brt_wb_prop*)d.data(); - - date1904 = h.f1904; - - break; - } - - default: - break; - } - }); - - // FIXME - preserve sheet order - - auto rels = read_relationships(fn, files); - - for (const auto& sr : sheets_rels) { - for (const auto& r : rels) { - if (r.first == sr.rid) { - auto name = filesystem::path(fn); - - // FIXME - can we resolve relative paths properly? - - name.remove_filename(); - name /= r.second; - - auto ns = name.string(); - - for (auto& c : ns) { - if (c == '\\') - c = '/'; - } - - if (files.count(ns) == 0) - Rcpp::stop("File {} not found.", ns); - - auto& d = files.at(ns).data; - - load_sheet_binary(sr.name, span((uint8_t*)d.data(), d.size()), sr.visible); - break; - } - } - } -} - -void workbook_pimpl::load_shared_strings_binary(span data) { - xlsb_walk(data, [&](enum xlsb_type type, span d) { - if (type == xlsb_type::BrtSSTItem) { - if (d.size() < offsetof(brt_sst_item, richStr.str)) - Rcpp::stop("Malformed BrtSSTItem record."); - - const auto& h = *(brt_sst_item*)d.data(); - - if (d.size() < offsetof(brt_sst_item, richStr.str) + (sizeof(char16_t) * h.richStr.len)) - Rcpp::stop("Malformed BrtSSTItem record."); - - auto u16sv = u16string_view(h.richStr.str, h.richStr.len); - - shared_strings2.emplace_back(utf16_to_utf8(u16sv)); - } - }); -} - -void workbook_pimpl::load_styles_binary(span data) { - bool in_numfmts = false, in_cellxfs = false; - - xlsb_walk(data, [&](enum xlsb_type type, span d) { - switch (type) { - case xlsb_type::BrtBeginCellXFs: - in_cellxfs = true; - break; - - case xlsb_type::BrtEndCellXFs: - in_cellxfs = false; - break; - - case xlsb_type::BrtBeginFmts: - in_numfmts = true; - break; - - case xlsb_type::BrtEndFmts: - in_numfmts = false; - break; - - case xlsb_type::BrtXF: - if (in_cellxfs) { - optional numfmtid; - - if (d.size() < sizeof(brt_xf)) - Rcpp::stop("Malformed BrtXF record."); - - const auto& h = *(brt_xf*)d.data(); - - numfmtid = h.iFmt; - - if (h.xfGrbitAtr & 1) - numfmtid = nullopt; - - cell_styles.push_back(numfmtid); - } - break; - - case xlsb_type::BrtFmt: - if (in_numfmts) { - if (d.size() < offsetof(brt_fmt, stFmtCode)) - Rcpp::stop("Malformed BrtFmt record."); - - const auto& h = *(brt_fmt*)d.data(); - - if (d.size() < offsetof(brt_fmt, stFmtCode) + (h.stFmtCode_len * sizeof(char16_t))) - Rcpp::stop("Malformed BrtFmt record."); - - auto u16sv = u16string_view(h.stFmtCode, h.stFmtCode_len); - auto s = utf16_to_utf8(u16sv); - - // FIXME - removing backslashes? - - number_formats[h.ifmt] = s; - } - break; - - default: - break; - } - }); -} - -}; diff --git a/src/xlcpp/xlsb.h b/src/xlcpp/xlsb.h deleted file mode 100644 index af02fd90d..000000000 --- a/src/xlcpp/xlsb.h +++ /dev/null @@ -1,2707 +0,0 @@ -#pragma once - -enum class xlsb_type { - BrtRowHdr = 0, - BrtCellBlank = 1, - BrtCellRk = 2, - BrtCellError = 3, - BrtCellBool = 4, - BrtCellReal = 5, - BrtCellSt = 6, - BrtCellIsst = 7, - BrtFmlaString = 8, - BrtFmlaNum = 9, - BrtFmlaBool = 10, - BrtFmlaError = 11, - BrtSSTItem = 19, - BrtPCDIMissing = 20, - BrtPCDINumber = 21, - BrtPCDIBoolean = 22, - BrtPCDIError = 23, - BrtPCDIString = 24, - BrtPCDIDatetime = 25, - BrtPCDIIndex = 26, - BrtPCDIAMissing = 27, - BrtPCDIANumber = 28, - BrtPCDIABoolean = 29, - BrtPCDIAError = 30, - BrtPCDIAString = 31, - BrtPCDIADatetime = 32, - BrtPCRRecord = 33, - BrtPCRRecordDt = 34, - BrtFRTBegin = 35, - BrtFRTEnd = 36, - BrtACBegin = 37, - BrtACEnd = 38, - BrtName = 39, - BrtIndexRowBlock = 40, - BrtIndexBlock = 42, - BrtFont = 43, - BrtFmt = 44, - BrtFill = 45, - BrtBorder = 46, - BrtXF = 47, - BrtStyle = 48, - BrtCellMeta = 49, - BrtValueMeta = 50, - BrtMdb = 51, - BrtBeginFmd = 52, - BrtEndFmd = 53, - BrtBeginMdx = 54, - BrtEndMdx = 55, - BrtBeginMdxTuple = 56, - BrtEndMdxTuple = 57, - BrtMdxMbrIstr = 58, - BrtStr = 59, - BrtColInfo = 60, - BrtCellRString = 62, - BrtDVal = 64, - BrtSxvcellNum = 65, - BrtSxvcellStr = 66, - BrtSxvcellBool = 67, - BrtSxvcellErr = 68, - BrtSxvcellDate = 69, - BrtSxvcellNil = 70, - BrtFileVersion = 128, - BrtBeginSheet = 129, - BrtEndSheet = 130, - BrtBeginBook = 131, - BrtEndBook = 132, - BrtBeginWsViews = 133, - BrtEndWsViews = 134, - BrtBeginBookViews = 135, - BrtEndBookViews = 136, - BrtBeginWsView = 137, - BrtEndWsView = 138, - BrtBeginCsViews = 139, - BrtEndCsViews = 140, - BrtBeginCsView = 141, - BrtEndCsView = 142, - BrtBeginBundleShs = 143, - BrtEndBundleShs = 144, - BrtBeginSheetData = 145, - BrtEndSheetData = 146, - BrtWsProp = 147, - BrtWsDim = 148, - BrtPane = 151, - BrtSel = 152, - BrtWbProp = 153, - BrtWbFactoid = 154, - BrtFileRecover = 155, - BrtBundleSh = 156, - BrtCalcProp = 157, - BrtBookView = 158, - BrtBeginSst = 159, - BrtEndSst = 160, - BrtBeginAFilter = 161, - BrtEndAFilter = 162, - BrtBeginFilterColumn = 163, - BrtEndFilterColumn = 164, - BrtBeginFilters = 165, - BrtEndFilters = 166, - BrtFilter = 167, - BrtColorFilter = 168, - BrtIconFilter = 169, - BrtTop10Filter = 170, - BrtDynamicFilter = 171, - BrtBeginCustomFilters = 172, - BrtEndCustomFilters = 173, - BrtCustomFilter = 174, - BrtAFilterDateGroupItem = 175, - BrtMergeCell = 176, - BrtBeginMergeCells = 177, - BrtEndMergeCells = 178, - BrtBeginPivotCacheDef = 179, - BrtEndPivotCacheDef = 180, - BrtBeginPCDFields = 181, - BrtEndPCDFields = 182, - BrtBeginPCDField = 183, - BrtEndPCDField = 184, - BrtBeginPCDSource = 185, - BrtEndPCDSource = 186, - BrtBeginPCDSRange = 187, - BrtEndPCDSRange = 188, - BrtBeginPCDFAtbl = 189, - BrtEndPCDFAtbl = 190, - BrtBeginPCDIRun = 191, - BrtEndPCDIRun = 192, - BrtBeginPivotCacheRecords = 193, - BrtEndPivotCacheRecords = 194, - BrtBeginPCDHierarchies = 195, - BrtEndPCDHierarchies = 196, - BrtBeginPCDHierarchy = 197, - BrtEndPCDHierarchy = 198, - BrtBeginPCDHFieldsUsage = 199, - BrtEndPCDHFieldsUsage = 200, - BrtBeginExtConnection = 201, - BrtEndExtConnection = 202, - BrtBeginECDbProps = 203, - BrtEndECDbProps = 204, - BrtBeginECOlapProps = 205, - BrtEndECOlapProps = 206, - BrtBeginPCDSConsol = 207, - BrtEndPCDSConsol = 208, - BrtBeginPCDSCPages = 209, - BrtEndPCDSCPages = 210, - BrtBeginPCDSCPage = 211, - BrtEndPCDSCPage = 212, - BrtBeginPCDSCPItem = 213, - BrtEndPCDSCPItem = 214, - BrtBeginPCDSCSets = 215, - BrtEndPCDSCSets = 216, - BrtBeginPCDSCSet = 217, - BrtEndPCDSCSet = 218, - BrtBeginPCDFGroup = 219, - BrtEndPCDFGroup = 220, - BrtBeginPCDFGItems = 221, - BrtEndPCDFGItems = 222, - BrtBeginPCDFGRange = 223, - BrtEndPCDFGRange = 224, - BrtBeginPCDFGDiscrete = 225, - BrtEndPCDFGDiscrete = 226, - BrtBeginPCDSDTupleCache = 227, - BrtEndPCDSDTupleCache = 228, - BrtBeginPCDSDTCEntries = 229, - BrtEndPCDSDTCEntries = 230, - BrtBeginPCDSDTCEMembers = 231, - BrtEndPCDSDTCEMembers = 232, - BrtBeginPCDSDTCEMember = 233, - BrtEndPCDSDTCEMember = 234, - BrtBeginPCDSDTCQueries = 235, - BrtEndPCDSDTCQueries = 236, - BrtBeginPCDSDTCQuery = 237, - BrtEndPCDSDTCQuery = 238, - BrtBeginPCDSDTCSets = 239, - BrtEndPCDSDTCSets = 240, - BrtBeginPCDSDTCSet = 241, - BrtEndPCDSDTCSet = 242, - BrtBeginPCDCalcItems = 243, - BrtEndPCDCalcItems = 244, - BrtBeginPCDCalcItem = 245, - BrtEndPCDCalcItem = 246, - BrtBeginPRule = 247, - BrtEndPRule = 248, - BrtBeginPRFilters = 249, - BrtEndPRFilters = 250, - BrtBeginPRFilter = 251, - BrtEndPRFilter = 252, - BrtBeginPNames = 253, - BrtEndPNames = 254, - BrtBeginPName = 255, - BrtEndPName = 256, - BrtBeginPNPairs = 257, - BrtEndPNPairs = 258, - BrtBeginPNPair = 259, - BrtEndPNPair = 260, - BrtBeginECWebProps = 261, - BrtEndECWebProps = 262, - BrtBeginEcWpTables = 263, - BrtEndECWPTables = 264, - BrtBeginECParams = 265, - BrtEndECParams = 266, - BrtBeginECParam = 267, - BrtEndECParam = 268, - BrtBeginPCDKPIs = 269, - BrtEndPCDKPIs = 270, - BrtBeginPCDKPI = 271, - BrtEndPCDKPI = 272, - BrtBeginDims = 273, - BrtEndDims = 274, - BrtBeginDim = 275, - BrtEndDim = 276, - BrtIndexPartEnd = 277, - BrtBeginStyleSheet = 278, - BrtEndStyleSheet = 279, - BrtBeginSXView = 280, - BrtEndSXVI = 281, - BrtBeginSXVI = 282, - BrtBeginSXVIs = 283, - BrtEndSXVIs = 284, - BrtBeginSXVD = 285, - BrtEndSXVD = 286, - BrtBeginSXVDs = 287, - BrtEndSXVDs = 288, - BrtBeginSXPI = 289, - BrtEndSXPI = 290, - BrtBeginSXPIs = 291, - BrtEndSXPIs = 292, - BrtBeginSXDI = 293, - BrtEndSXDI = 294, - BrtBeginSXDIs = 295, - BrtEndSXDIs = 296, - BrtBeginSXLI = 297, - BrtEndSXLI = 298, - BrtBeginSXLIRws = 299, - BrtEndSXLIRws = 300, - BrtBeginSXLICols = 301, - BrtEndSXLICols = 302, - BrtBeginSXFormat = 303, - BrtEndSXFormat = 304, - BrtBeginSXFormats = 305, - BrtEndSxFormats = 306, - BrtBeginSxSelect = 307, - BrtEndSxSelect = 308, - BrtBeginISXVDRws = 309, - BrtEndISXVDRws = 310, - BrtBeginISXVDCols = 311, - BrtEndISXVDCols = 312, - BrtEndSXLocation = 313, - BrtBeginSXLocation = 314, - BrtEndSXView = 315, - BrtBeginSXTHs = 316, - BrtEndSXTHs = 317, - BrtBeginSXTH = 318, - BrtEndSXTH = 319, - BrtBeginISXTHRws = 320, - BrtEndISXTHRws = 321, - BrtBeginISXTHCols = 322, - BrtEndISXTHCols = 323, - BrtBeginSXTDMPS = 324, - BrtEndSXTDMPs = 325, - BrtBeginSXTDMP = 326, - BrtEndSXTDMP = 327, - BrtBeginSXTHItems = 328, - BrtEndSXTHItems = 329, - BrtBeginSXTHItem = 330, - BrtEndSXTHItem = 331, - BrtBeginMetadata = 332, - BrtEndMetadata = 333, - BrtBeginEsmdtinfo = 334, - BrtMdtinfo = 335, - BrtEndEsmdtinfo = 336, - BrtBeginEsmdb = 337, - BrtEndEsmdb = 338, - BrtBeginEsfmd = 339, - BrtEndEsfmd = 340, - BrtBeginSingleCells = 341, - BrtEndSingleCells = 342, - BrtBeginList = 343, - BrtEndList = 344, - BrtBeginListCols = 345, - BrtEndListCols = 346, - BrtBeginListCol = 347, - BrtEndListCol = 348, - BrtBeginListXmlCPr = 349, - BrtEndListXmlCPr = 350, - BrtListCCFmla = 351, - BrtListTrFmla = 352, - BrtBeginExternals = 353, - BrtEndExternals = 354, - BrtSupBookSrc = 355, - BrtSupSelf = 357, - BrtSupSame = 358, - BrtSupTabs = 359, - BrtBeginSupBook = 360, - BrtPlaceholderName = 361, - BrtExternSheet = 362, - BrtExternTableStart = 363, - BrtExternTableEnd = 364, - BrtExternRowHdr = 366, - BrtExternCellBlank = 367, - BrtExternCellReal = 368, - BrtExternCellBool = 369, - BrtExternCellError = 370, - BrtExternCellString = 371, - BrtBeginEsmdx = 372, - BrtEndEsmdx = 373, - BrtBeginMdxSet = 374, - BrtEndMdxSet = 375, - BrtBeginMdxMbrProp = 376, - BrtEndMdxMbrProp = 377, - BrtBeginMdxKPI = 378, - BrtEndMdxKPI = 379, - BrtBeginEsstr = 380, - BrtEndEsstr = 381, - BrtBeginPRFItem = 382, - BrtEndPRFItem = 383, - BrtBeginPivotCacheIDs = 384, - BrtEndPivotCacheIDs = 385, - BrtBeginPivotCacheID = 386, - BrtEndPivotCacheID = 387, - BrtBeginISXVIs = 388, - BrtEndISXVIs = 389, - BrtBeginColInfos = 390, - BrtEndColInfos = 391, - BrtBeginRwBrk = 392, - BrtEndRwBrk = 393, - BrtBeginColBrk = 394, - BrtEndColBrk = 395, - BrtBrk = 396, - BrtUserBookView = 397, - BrtInfo = 398, - BrtCUsr = 399, - BrtUsr = 400, - BrtBeginUsers = 401, - BrtEOF = 403, - BrtUCR = 404, - BrtRRInsDel = 405, - BrtRREndInsDel = 406, - BrtRRMove = 407, - BrtRREndMove = 408, - BrtRRChgCell = 409, - BrtRREndChgCell = 410, - BrtRRHeader = 411, - BrtRRUserView = 412, - BrtRRRenSheet = 413, - BrtRRInsertSh = 414, - BrtRRDefName = 415, - BrtRRNote = 416, - BrtRRConflict = 417, - BrtRRTQSIF = 418, - BrtRRFormat = 419, - BrtRREndFormat = 420, - BrtRRAutoFmt = 421, - BrtBeginUserShViews = 422, - BrtBeginUserShView = 423, - BrtEndUserShView = 424, - BrtEndUserShViews = 425, - BrtArrFmla = 426, - BrtShrFmla = 427, - BrtTable = 428, - BrtBeginExtConnections = 429, - BrtEndExtConnections = 430, - BrtBeginPCDCalcMems = 431, - BrtEndPCDCalcMems = 432, - BrtBeginPCDCalcMem = 433, - BrtEndPCDCalcMem = 434, - BrtBeginPCDHGLevels = 435, - BrtEndPCDHGLevels = 436, - BrtBeginPCDHGLevel = 437, - BrtEndPCDHGLevel = 438, - BrtBeginPCDHGLGroups = 439, - BrtEndPCDHGLGroups = 440, - BrtBeginPCDHGLGroup = 441, - BrtEndPCDHGLGroup = 442, - BrtBeginPCDHGLGMembers = 443, - BrtEndPCDHGLGMembers = 444, - BrtBeginPCDHGLGMember = 445, - BrtEndPCDHGLGMember = 446, - BrtBeginQSI = 447, - BrtEndQSI = 448, - BrtBeginQSIR = 449, - BrtEndQSIR = 450, - BrtBeginDeletedNames = 451, - BrtEndDeletedNames = 452, - BrtBeginDeletedName = 453, - BrtEndDeletedName = 454, - BrtBeginQSIFs = 455, - BrtEndQSIFs = 456, - BrtBeginQSIF = 457, - BrtEndQSIF = 458, - BrtBeginAutoSortScope = 459, - BrtEndAutoSortScope = 460, - BrtBeginConditionalFormatting = 461, - BrtEndConditionalFormatting = 462, - BrtBeginCFRule = 463, - BrtEndCFRule = 464, - BrtBeginIconSet = 465, - BrtEndIconSet = 466, - BrtBeginDatabar = 467, - BrtEndDatabar = 468, - BrtBeginColorScale = 469, - BrtEndColorScale = 470, - BrtCFVO = 471, - BrtExternValueMeta = 472, - BrtBeginColorPalette = 473, - BrtEndColorPalette = 474, - BrtIndexedColor = 475, - BrtMargins = 476, - BrtPrintOptions = 477, - BrtPageSetup = 478, - BrtBeginHeaderFooter = 479, - BrtEndHeaderFooter = 480, - BrtBeginSXCrtFormat = 481, - BrtEndSXCrtFormat = 482, - BrtBeginSXCrtFormats = 483, - BrtEndSXCrtFormats = 484, - BrtWsFmtInfo = 485, - BrtBeginMgs = 486, - BrtEndMGs = 487, - BrtBeginMGMaps = 488, - BrtEndMGMaps = 489, - BrtBeginMG = 490, - BrtEndMG = 491, - BrtBeginMap = 492, - BrtEndMap = 493, - BrtHLink = 494, - BrtBeginDCon = 495, - BrtEndDCon = 496, - BrtBeginDRefs = 497, - BrtEndDRefs = 498, - BrtDRef = 499, - BrtBeginScenMan = 500, - BrtEndScenMan = 501, - BrtBeginSct = 502, - BrtEndSct = 503, - BrtSlc = 504, - BrtBeginDXFs = 505, - BrtEndDXFs = 506, - BrtDXF = 507, - BrtBeginTableStyles = 508, - BrtEndTableStyles = 509, - BrtBeginTableStyle = 510, - BrtEndTableStyle = 511, - BrtTableStyleElement = 512, - BrtTableStyleClient = 513, - BrtBeginVolDeps = 514, - BrtEndVolDeps = 515, - BrtBeginVolType = 516, - BrtEndVolType = 517, - BrtBeginVolMain = 518, - BrtEndVolMain = 519, - BrtBeginVolTopic = 520, - BrtEndVolTopic = 521, - BrtVolSubtopic = 522, - BrtVolRef = 523, - BrtVolNum = 524, - BrtVolErr = 525, - BrtVolStr = 526, - BrtVolBool = 527, - BrtBeginSortState = 530, - BrtEndSortState = 531, - BrtBeginSortCond = 532, - BrtEndSortCond = 533, - BrtBookProtection = 534, - BrtSheetProtection = 535, - BrtRangeProtection = 536, - BrtPhoneticInfo = 537, - BrtBeginECTxtWiz = 538, - BrtEndECTxtWiz = 539, - BrtBeginECTWFldInfoLst = 540, - BrtEndECTWFldInfoLst = 541, - BrtBeginECTwFldInfo = 542, - BrtFileSharing = 548, - BrtOleSize = 549, - BrtDrawing = 550, - BrtLegacyDrawing = 551, - BrtLegacyDrawingHF = 552, - BrtWebOpt = 553, - BrtBeginWebPubItems = 554, - BrtEndWebPubItems = 555, - BrtBeginWebPubItem = 556, - BrtEndWebPubItem = 557, - BrtBeginSXCondFmt = 558, - BrtEndSXCondFmt = 559, - BrtBeginSXCondFmts = 560, - BrtEndSXCondFmts = 561, - BrtBkHim = 562, - BrtColor = 564, - BrtBeginIndexedColors = 565, - BrtEndIndexedColors = 566, - BrtBeginMRUColors = 569, - BrtEndMRUColors = 570, - BrtMRUColor = 572, - BrtBeginDVals = 573, - BrtEndDVals = 574, - BrtSupNameStart = 577, - BrtSupNameValueStart = 578, - BrtSupNameValueEnd = 579, - BrtSupNameNum = 580, - BrtSupNameErr = 581, - BrtSupNameSt = 582, - BrtSupNameNil = 583, - BrtSupNameBool = 584, - BrtSupNameFmla = 585, - BrtSupNameBits = 586, - BrtSupNameEnd = 587, - BrtEndSupBook = 588, - BrtCellSmartTagProperty = 589, - BrtBeginCellSmartTag = 590, - BrtEndCellSmartTag = 591, - BrtBeginCellSmartTags = 592, - BrtEndCellSmartTags = 593, - BrtBeginSmartTags = 594, - BrtEndSmartTags = 595, - BrtSmartTagType = 596, - BrtBeginSmartTagTypes = 597, - BrtEndSmartTagTypes = 598, - BrtBeginSXFilters = 599, - BrtEndSXFilters = 600, - BrtBeginSXFILTER = 601, - BrtEndSXFilter = 602, - BrtBeginFills = 603, - BrtEndFills = 604, - BrtBeginCellWatches = 605, - BrtEndCellWatches = 606, - BrtCellWatch = 607, - BrtBeginCRErrs = 608, - BrtEndCRErrs = 609, - BrtCrashRecErr = 610, - BrtBeginFonts = 611, - BrtEndFonts = 612, - BrtBeginBorders = 613, - BrtEndBorders = 614, - BrtBeginFmts = 615, - BrtEndFmts = 616, - BrtBeginCellXFs = 617, - BrtEndCellXFs = 618, - BrtBeginStyles = 619, - BrtEndStyles = 620, - BrtBigName = 625, - BrtBeginCellStyleXFs = 626, - BrtEndCellStyleXFs = 627, - BrtBeginComments = 628, - BrtEndComments = 629, - BrtBeginCommentAuthors = 630, - BrtEndCommentAuthors = 631, - BrtCommentAuthor = 632, - BrtBeginCommentList = 633, - BrtEndCommentList = 634, - BrtBeginComment = 635, - BrtEndComment = 636, - BrtCommentText = 637, - BrtBeginOleObjects = 638, - BrtOleObject = 639, - BrtEndOleObjects = 640, - BrtBeginSxrules = 641, - BrtEndSxRules = 642, - BrtBeginActiveXControls = 643, - BrtActiveX = 644, - BrtEndActiveXControls = 645, - BrtBeginPCDSDTCEMembersSortBy = 646, - BrtBeginCellIgnoreECs = 648, - BrtCellIgnoreEC = 649, - BrtEndCellIgnoreECs = 650, - BrtCsProp = 651, - BrtCsPageSetup = 652, - BrtBeginUserCsViews = 653, - BrtEndUserCsViews = 654, - BrtBeginUserCsView = 655, - BrtEndUserCsView = 656, - BrtBeginPcdSFCIEntries = 657, - BrtEndPCDSFCIEntries = 658, - BrtPCDSFCIEntry = 659, - BrtBeginListParts = 660, - BrtListPart = 661, - BrtEndListParts = 662, - BrtSheetCalcProp = 663, - BrtBeginFnGroup = 664, - BrtFnGroup = 665, - BrtEndFnGroup = 666, - BrtSupAddin = 667, - BrtSXTDMPOrder = 668, - BrtCsProtection = 669, - BrtBeginWsSortMap = 671, - BrtEndWsSortMap = 672, - BrtBeginRRSort = 673, - BrtEndRRSort = 674, - BrtRRSortItem = 675, - BrtFileSharingIso = 676, - BrtBookProtectionIso = 677, - BrtSheetProtectionIso = 678, - BrtCsProtectionIso = 679, - BrtRangeProtectionIso = 680, - BrtDValList = 681, - BrtRwDescent = 1024, - BrtKnownFonts = 1025, - BrtBeginSXTupleSet = 1026, - BrtEndSXTupleSet = 1027, - BrtBeginSXTupleSetHeader = 1028, - BrtEndSXTupleSetHeader = 1029, - BrtSXTupleSetHeaderItem = 1030, - BrtBeginSXTupleSetData = 1031, - BrtEndSXTupleSetData = 1032, - BrtBeginSXTupleSetRow = 1033, - BrtEndSXTupleSetRow = 1034, - BrtSXTupleSetRowItem = 1035, - BrtNameExt = 1036, - BrtPCDH14 = 1037, - BrtBeginPCDCalcMem14 = 1038, - BrtEndPCDCalcMem14 = 1039, - BrtSXTH14 = 1040, - BrtBeginSparklineGroup = 1041, - BrtEndSparklineGroup = 1042, - BrtSparkline = 1043, - BrtSXDI14 = 1044, - BrtWsFmtInfoEx14 = 1045, - BrtBeginConditionalFormatting14 = 1046, - BrtEndConditionalFormatting14 = 1047, - BrtBeginCFRule14 = 1048, - BrtEndCFRule14 = 1049, - BrtCFVO14 = 1050, - BrtBeginDatabar14 = 1051, - BrtBeginIconSet14 = 1052, - BrtDVal14 = 1053, - BrtBeginDVals14 = 1054, - BrtColor14 = 1055, - BrtBeginSparklines = 1056, - BrtEndSparklines = 1057, - BrtBeginSparklineGroups = 1058, - BrtEndSparklineGroups = 1059, - BrtSXVD14 = 1061, - BrtBeginSxView14 = 1062, - BrtEndSxView14 = 1063, - BrtBeginSXView16 = 1064, - BrtEndSXView16 = 1065, - BrtBeginPCD14 = 1066, - BrtEndPCD14 = 1067, - BrtBeginExtConn14 = 1068, - BrtEndExtConn14 = 1069, - BrtBeginSlicerCacheIDs = 1070, - BrtEndSlicerCacheIDs = 1071, - BrtBeginSlicerCacheID = 1072, - BrtEndSlicerCacheID = 1073, - BrtBeginSlicerCache = 1075, - BrtEndSlicerCache = 1076, - BrtBeginSlicerCacheDef = 1077, - BrtEndSlicerCacheDef = 1078, - BrtBeginSlicersEx = 1079, - BrtEndSlicersEx = 1080, - BrtBeginSlicerEx = 1081, - BrtEndSlicerEx = 1082, - BrtBeginSlicer = 1083, - BrtEndSlicer = 1084, - BrtSlicerCachePivotTables = 1085, - BrtBeginSlicerCacheOlapImpl = 1086, - BrtEndSlicerCacheOlapImpl = 1087, - BrtBeginSlicerCacheLevelsData = 1088, - BrtEndSlicerCacheLevelsData = 1089, - BrtBeginSlicerCacheLevelData = 1090, - BrtEndSlicerCacheLevelData = 1091, - BrtBeginSlicerCacheSiRanges = 1092, - BrtEndSlicerCacheSiRanges = 1093, - BrtBeginSlicerCacheSiRange = 1094, - BrtEndSlicerCacheSiRange = 1095, - BrtSlicerCacheOlapItem = 1096, - BrtBeginSlicerCacheSelections = 1097, - BrtSlicerCacheSelection = 1098, - BrtEndSlicerCacheSelections = 1099, - BrtBeginSlicerCacheNative = 1100, - BrtEndSlicerCacheNative = 1101, - BrtSlicerCacheNativeItem = 1102, - BrtRangeProtection14 = 1103, - BrtRangeProtectionIso14 = 1104, - BrtCellIgnoreEC14 = 1105, - BrtList14 = 1111, - BrtCFIcon = 1112, - BrtBeginSlicerCachesPivotCacheIDs = 1113, - BrtEndSlicerCachesPivotCacheIDs = 1114, - BrtBeginSlicers = 1115, - BrtEndSlicers = 1116, - BrtWbProp14 = 1117, - BrtBeginSXEdit = 1118, - BrtEndSXEdit = 1119, - BrtBeginSXEdits = 1120, - BrtEndSXEdits = 1121, - BrtBeginSXChange = 1122, - BrtEndSXChange = 1123, - BrtBeginSXChanges = 1124, - BrtEndSXChanges = 1125, - BrtSXTupleItems = 1126, - BrtBeginSlicerStyle = 1128, - BrtEndSlicerStyle = 1129, - BrtSlicerStyleElement = 1130, - BrtBeginStyleSheetExt14 = 1131, - BrtEndStyleSheetExt14 = 1132, - BrtBeginSlicerCachesPivotCacheID = 1133, - BrtEndSlicerCachesPivotCacheID = 1134, - BrtBeginConditionalFormattings = 1135, - BrtEndConditionalFormattings = 1136, - BrtBeginPCDCalcMemExt = 1137, - BrtEndPCDCalcMemExt = 1138, - BrtBeginPCDCalcMemsExt = 1139, - BrtEndPCDCalcMemsExt = 1140, - BrtPCDField14 = 1141, - BrtBeginSlicerStyles = 1142, - BrtEndSlicerStyles = 1143, - BrtBeginSlicerStyleElements = 1144, - BrtEndSlicerStyleElements = 1145, - BrtCFRuleExt = 1146, - BrtBeginSXCondFmt14 = 1147, - BrtEndSXCondFmt14 = 1148, - BrtBeginSXCondFmts14 = 1149, - BrtEndSXCondFmts14 = 1150, - BrtBeginSortCond14 = 1152, - BrtEndSortCond14 = 1153, - BrtEndDVals14 = 1154, - BrtEndIconSet14 = 1155, - BrtEndDatabar14 = 1156, - BrtBeginColorScale14 = 1157, - BrtEndColorScale14 = 1158, - BrtBeginSxrules14 = 1159, - BrtEndSxrules14 = 1160, - BrtBeginPRule14 = 1161, - BrtEndPRule14 = 1162, - BrtBeginPRFilters14 = 1163, - BrtEndPRFilters14 = 1164, - BrtBeginPRFilter14 = 1165, - BrtEndPRFilter14 = 1166, - BrtBeginPRFItem14 = 1167, - BrtEndPRFItem14 = 1168, - BrtBeginCellIgnoreECs14 = 1169, - BrtEndCellIgnoreECs14 = 1170, - BrtDxf14 = 1171, - BrtBeginDxF14s = 1172, - BrtEndDxf14s = 1173, - BrtFilter14 = 1177, - BrtBeginCustomFilters14 = 1178, - BrtCustomFilter14 = 1180, - BrtIconFilter14 = 1181, - BrtPivotCacheConnectionName = 1182, - BrtBeginDecoupledPivotCacheIDs = 2048, - BrtEndDecoupledPivotCacheIDs = 2049, - BrtDecoupledPivotCacheID = 2050, - BrtBeginPivotTableRefs = 2051, - BrtEndPivotTableRefs = 2052, - BrtPivotTableRef = 2053, - BrtSlicerCacheBookPivotTables = 2054, - BrtBeginSxvcells = 2055, - BrtEndSxvcells = 2056, - BrtBeginSxRow = 2057, - BrtEndSxRow = 2058, - BrtPcdCalcMem15 = 2060, - BrtQsi15 = 2067, - BrtBeginWebExtensions = 2068, - BrtEndWebExtensions = 2069, - BrtWebExtension = 2070, - BrtAbsPath15 = 2071, - BrtBeginPivotTableUISettings = 2072, - BrtEndPivotTableUISettings = 2073, - BrtTableSlicerCacheIDs = 2075, - BrtTableSlicerCacheID = 2076, - BrtBeginTableSlicerCache = 2077, - BrtEndTableSlicerCache = 2078, - BrtSxFilter15 = 2079, - BrtBeginTimelineCachePivotCacheIDs = 2080, - BrtEndTimelineCachePivotCacheIDs = 2081, - BrtTimelineCachePivotCacheID = 2082, - BrtBeginTimelineCacheIDs = 2083, - BrtEndTimelineCacheIDs = 2084, - BrtBeginTimelineCacheID = 2085, - BrtEndTimelineCacheID = 2086, - BrtBeginTimelinesEx = 2087, - BrtEndTimelinesEx = 2088, - BrtBeginTimelineEx = 2089, - BrtEndTimelineEx = 2090, - BrtWorkBookPr15 = 2091, - BrtPCDH15 = 2092, - BrtBeginTimelineStyle = 2093, - BrtEndTimelineStyle = 2094, - BrtTimelineStyleElement = 2095, - BrtBeginTimelineStylesheetExt15 = 2096, - BrtEndTimelineStylesheetExt15 = 2097, - BrtBeginTimelineStyles = 2098, - BrtEndTimelineStyles = 2099, - BrtBeginTimelineStyleElements = 2100, - BrtEndTimelineStyleElements = 2101, - BrtDxf15 = 2102, - BrtBeginDxfs15 = 2103, - BrtEndDXFs15 = 2104, - BrtSlicerCacheHideItemsWithNoData = 2105, - BrtBeginItemUniqueNames = 2106, - BrtEndItemUniqueNames = 2107, - BrtItemUniqueName = 2108, - BrtBeginExtConn15 = 2109, - BrtEndExtConn15 = 2110, - BrtBeginOledbPr15 = 2111, - BrtEndOledbPr15 = 2112, - BrtBeginDataFeedPr15 = 2113, - BrtEndDataFeedPr15 = 2114, - BrtTextPr15 = 2115, - BrtRangePr15 = 2116, - BrtDbCommand15 = 2117, - BrtBeginDbTables15 = 2118, - BrtEndDbTables15 = 2119, - BrtDbTable15 = 2120, - BrtBeginDataModel = 2121, - BrtEndDataModel = 2122, - BrtBeginModelTables = 2123, - BrtEndModelTables = 2124, - BrtModelTable = 2125, - BrtBeginModelRelationships = 2126, - BrtEndModelRelationships = 2127, - BrtModelRelationship = 2128, - BrtBeginECTxtWiz15 = 2129, - BrtEndECTxtWiz15 = 2130, - BrtBeginECTWFldInfoLst15 = 2131, - BrtEndECTWFldInfoLst15 = 2132, - BrtBeginECTWFldInfo15 = 2133, - BrtFieldListActiveItem = 2134, - BrtPivotCacheIdVersion = 2135, - BrtSXDI15 = 2136, - brtBeginModelTimeGroupings = 2137, - brtEndModelTimeGroupings = 2138, - brtBeginModelTimeGrouping = 2139, - brtEndModelTimeGrouping = 2140, - brtModelTimeGroupingCalcCol = 2141, - brtRevisionPtr = 3073, - BrtBeginDynamicArrayPr = 4096, - BrtEndDynamicArrayPr = 4097, - BrtBeginRichValueBlock = 5002, - BrtEndRichValueBlock = 5003, - BrtBeginRichFilters = 5081, - BrtEndRichFilters = 5082, - BrtRichFilter = 5083, - BrtBeginRichFilterColumn = 5084, - BrtEndRichFilterColumn = 5085, - BrtBeginCustomRichFilters = 5086, - BrtEndCustomRichFilters = 5087, - BRTCustomRichFilter = 5088, - BrtTop10RichFilter = 5089, - BrtDynamicRichFilter = 5090, - BrtBeginRichSortCondition = 5092, - BrtEndRichSortCondition = 5093, - BrtRichFilterDateGroupItem = 5094, - BrtBeginCalcFeatures = 5095, - BrtEndCalcFeatures = 5096, - BrtCalcFeature = 5097, - BrtExternalLinksPr = 5099 -}; - -template<> -struct fmt::formatter { - constexpr auto parse(format_parse_context& ctx) { - auto it = ctx.begin(); - - if (it != ctx.end() && *it != '}') - throw format_error("invalid format"); - - return it; - } - - template - auto format(enum xlsb_type t, format_context& ctx) const { - switch (t) { - case xlsb_type::BrtRowHdr: - return fmt::format_to(ctx.out(), "BrtRowHdr"); - case xlsb_type::BrtCellBlank: - return fmt::format_to(ctx.out(), "BrtCellBlank"); - case xlsb_type::BrtCellRk: - return fmt::format_to(ctx.out(), "BrtCellRk"); - case xlsb_type::BrtCellError: - return fmt::format_to(ctx.out(), "BrtCellError"); - case xlsb_type::BrtCellBool: - return fmt::format_to(ctx.out(), "BrtCellBool"); - case xlsb_type::BrtCellReal: - return fmt::format_to(ctx.out(), "BrtCellReal"); - case xlsb_type::BrtCellSt: - return fmt::format_to(ctx.out(), "BrtCellSt"); - case xlsb_type::BrtCellIsst: - return fmt::format_to(ctx.out(), "BrtCellIsst"); - case xlsb_type::BrtFmlaString: - return fmt::format_to(ctx.out(), "BrtFmlaString"); - case xlsb_type::BrtFmlaNum: - return fmt::format_to(ctx.out(), "BrtFmlaNum"); - case xlsb_type::BrtFmlaBool: - return fmt::format_to(ctx.out(), "BrtFmlaBool"); - case xlsb_type::BrtFmlaError: - return fmt::format_to(ctx.out(), "BrtFmlaError"); - case xlsb_type::BrtSSTItem: - return fmt::format_to(ctx.out(), "BrtSSTItem"); - case xlsb_type::BrtPCDIMissing: - return fmt::format_to(ctx.out(), "BrtPCDIMissing"); - case xlsb_type::BrtPCDINumber: - return fmt::format_to(ctx.out(), "BrtPCDINumber"); - case xlsb_type::BrtPCDIBoolean: - return fmt::format_to(ctx.out(), "BrtPCDIBoolean"); - case xlsb_type::BrtPCDIError: - return fmt::format_to(ctx.out(), "BrtPCDIError"); - case xlsb_type::BrtPCDIString: - return fmt::format_to(ctx.out(), "BrtPCDIString"); - case xlsb_type::BrtPCDIDatetime: - return fmt::format_to(ctx.out(), "BrtPCDIDatetime"); - case xlsb_type::BrtPCDIIndex: - return fmt::format_to(ctx.out(), "BrtPCDIIndex"); - case xlsb_type::BrtPCDIAMissing: - return fmt::format_to(ctx.out(), "BrtPCDIAMissing"); - case xlsb_type::BrtPCDIANumber: - return fmt::format_to(ctx.out(), "BrtPCDIANumber"); - case xlsb_type::BrtPCDIABoolean: - return fmt::format_to(ctx.out(), "BrtPCDIABoolean"); - case xlsb_type::BrtPCDIAError: - return fmt::format_to(ctx.out(), "BrtPCDIAError"); - case xlsb_type::BrtPCDIAString: - return fmt::format_to(ctx.out(), "BrtPCDIAString"); - case xlsb_type::BrtPCDIADatetime: - return fmt::format_to(ctx.out(), "BrtPCDIADatetime"); - case xlsb_type::BrtPCRRecord: - return fmt::format_to(ctx.out(), "BrtPCRRecord"); - case xlsb_type::BrtPCRRecordDt: - return fmt::format_to(ctx.out(), "BrtPCRRecordDt"); - case xlsb_type::BrtFRTBegin: - return fmt::format_to(ctx.out(), "BrtFRTBegin"); - case xlsb_type::BrtFRTEnd: - return fmt::format_to(ctx.out(), "BrtFRTEnd"); - case xlsb_type::BrtACBegin: - return fmt::format_to(ctx.out(), "BrtACBegin"); - case xlsb_type::BrtACEnd: - return fmt::format_to(ctx.out(), "BrtACEnd"); - case xlsb_type::BrtName: - return fmt::format_to(ctx.out(), "BrtName"); - case xlsb_type::BrtIndexRowBlock: - return fmt::format_to(ctx.out(), "BrtIndexRowBlock"); - case xlsb_type::BrtIndexBlock: - return fmt::format_to(ctx.out(), "BrtIndexBlock"); - case xlsb_type::BrtFont: - return fmt::format_to(ctx.out(), "BrtFont"); - case xlsb_type::BrtFmt: - return fmt::format_to(ctx.out(), "BrtFmt"); - case xlsb_type::BrtFill: - return fmt::format_to(ctx.out(), "BrtFill"); - case xlsb_type::BrtBorder: - return fmt::format_to(ctx.out(), "BrtBorder"); - case xlsb_type::BrtXF: - return fmt::format_to(ctx.out(), "BrtXF"); - case xlsb_type::BrtStyle: - return fmt::format_to(ctx.out(), "BrtStyle"); - case xlsb_type::BrtCellMeta: - return fmt::format_to(ctx.out(), "BrtCellMeta"); - case xlsb_type::BrtValueMeta: - return fmt::format_to(ctx.out(), "BrtValueMeta"); - case xlsb_type::BrtMdb: - return fmt::format_to(ctx.out(), "BrtMdb"); - case xlsb_type::BrtBeginFmd: - return fmt::format_to(ctx.out(), "BrtBeginFmd"); - case xlsb_type::BrtEndFmd: - return fmt::format_to(ctx.out(), "BrtEndFmd"); - case xlsb_type::BrtBeginMdx: - return fmt::format_to(ctx.out(), "BrtBeginMdx"); - case xlsb_type::BrtEndMdx: - return fmt::format_to(ctx.out(), "BrtEndMdx"); - case xlsb_type::BrtBeginMdxTuple: - return fmt::format_to(ctx.out(), "BrtBeginMdxTuple"); - case xlsb_type::BrtEndMdxTuple: - return fmt::format_to(ctx.out(), "BrtEndMdxTuple"); - case xlsb_type::BrtMdxMbrIstr: - return fmt::format_to(ctx.out(), "BrtMdxMbrIstr"); - case xlsb_type::BrtStr: - return fmt::format_to(ctx.out(), "BrtStr"); - case xlsb_type::BrtColInfo: - return fmt::format_to(ctx.out(), "BrtColInfo"); - case xlsb_type::BrtCellRString: - return fmt::format_to(ctx.out(), "BrtCellRString"); - case xlsb_type::BrtDVal: - return fmt::format_to(ctx.out(), "BrtDVal"); - case xlsb_type::BrtSxvcellNum: - return fmt::format_to(ctx.out(), "BrtSxvcellNum"); - case xlsb_type::BrtSxvcellStr: - return fmt::format_to(ctx.out(), "BrtSxvcellStr"); - case xlsb_type::BrtSxvcellBool: - return fmt::format_to(ctx.out(), "BrtSxvcellBool"); - case xlsb_type::BrtSxvcellErr: - return fmt::format_to(ctx.out(), "BrtSxvcellErr"); - case xlsb_type::BrtSxvcellDate: - return fmt::format_to(ctx.out(), "BrtSxvcellDate"); - case xlsb_type::BrtSxvcellNil: - return fmt::format_to(ctx.out(), "BrtSxvcellNil"); - case xlsb_type::BrtFileVersion: - return fmt::format_to(ctx.out(), "BrtFileVersion"); - case xlsb_type::BrtBeginSheet: - return fmt::format_to(ctx.out(), "BrtBeginSheet"); - case xlsb_type::BrtEndSheet: - return fmt::format_to(ctx.out(), "BrtEndSheet"); - case xlsb_type::BrtBeginBook: - return fmt::format_to(ctx.out(), "BrtBeginBook"); - case xlsb_type::BrtEndBook: - return fmt::format_to(ctx.out(), "BrtEndBook"); - case xlsb_type::BrtBeginWsViews: - return fmt::format_to(ctx.out(), "BrtBeginWsViews"); - case xlsb_type::BrtEndWsViews: - return fmt::format_to(ctx.out(), "BrtEndWsViews"); - case xlsb_type::BrtBeginBookViews: - return fmt::format_to(ctx.out(), "BrtBeginBookViews"); - case xlsb_type::BrtEndBookViews: - return fmt::format_to(ctx.out(), "BrtEndBookViews"); - case xlsb_type::BrtBeginWsView: - return fmt::format_to(ctx.out(), "BrtBeginWsView"); - case xlsb_type::BrtEndWsView: - return fmt::format_to(ctx.out(), "BrtEndWsView"); - case xlsb_type::BrtBeginCsViews: - return fmt::format_to(ctx.out(), "BrtBeginCsViews"); - case xlsb_type::BrtEndCsViews: - return fmt::format_to(ctx.out(), "BrtEndCsViews"); - case xlsb_type::BrtBeginCsView: - return fmt::format_to(ctx.out(), "BrtBeginCsView"); - case xlsb_type::BrtEndCsView: - return fmt::format_to(ctx.out(), "BrtEndCsView"); - case xlsb_type::BrtBeginBundleShs: - return fmt::format_to(ctx.out(), "BrtBeginBundleShs"); - case xlsb_type::BrtEndBundleShs: - return fmt::format_to(ctx.out(), "BrtEndBundleShs"); - case xlsb_type::BrtBeginSheetData: - return fmt::format_to(ctx.out(), "BrtBeginSheetData"); - case xlsb_type::BrtEndSheetData: - return fmt::format_to(ctx.out(), "BrtEndSheetData"); - case xlsb_type::BrtWsProp: - return fmt::format_to(ctx.out(), "BrtWsProp"); - case xlsb_type::BrtWsDim: - return fmt::format_to(ctx.out(), "BrtWsDim"); - case xlsb_type::BrtPane: - return fmt::format_to(ctx.out(), "BrtPane"); - case xlsb_type::BrtSel: - return fmt::format_to(ctx.out(), "BrtSel"); - case xlsb_type::BrtWbProp: - return fmt::format_to(ctx.out(), "BrtWbProp"); - case xlsb_type::BrtWbFactoid: - return fmt::format_to(ctx.out(), "BrtWbFactoid"); - case xlsb_type::BrtFileRecover: - return fmt::format_to(ctx.out(), "BrtFileRecover"); - case xlsb_type::BrtBundleSh: - return fmt::format_to(ctx.out(), "BrtBundleSh"); - case xlsb_type::BrtCalcProp: - return fmt::format_to(ctx.out(), "BrtCalcProp"); - case xlsb_type::BrtBookView: - return fmt::format_to(ctx.out(), "BrtBookView"); - case xlsb_type::BrtBeginSst: - return fmt::format_to(ctx.out(), "BrtBeginSst"); - case xlsb_type::BrtEndSst: - return fmt::format_to(ctx.out(), "BrtEndSst"); - case xlsb_type::BrtBeginAFilter: - return fmt::format_to(ctx.out(), "BrtBeginAFilter"); - case xlsb_type::BrtEndAFilter: - return fmt::format_to(ctx.out(), "BrtEndAFilter"); - case xlsb_type::BrtBeginFilterColumn: - return fmt::format_to(ctx.out(), "BrtBeginFilterColumn"); - case xlsb_type::BrtEndFilterColumn: - return fmt::format_to(ctx.out(), "BrtEndFilterColumn"); - case xlsb_type::BrtBeginFilters: - return fmt::format_to(ctx.out(), "BrtBeginFilters"); - case xlsb_type::BrtEndFilters: - return fmt::format_to(ctx.out(), "BrtEndFilters"); - case xlsb_type::BrtFilter: - return fmt::format_to(ctx.out(), "BrtFilter"); - case xlsb_type::BrtColorFilter: - return fmt::format_to(ctx.out(), "BrtColorFilter"); - case xlsb_type::BrtIconFilter: - return fmt::format_to(ctx.out(), "BrtIconFilter"); - case xlsb_type::BrtTop10Filter: - return fmt::format_to(ctx.out(), "BrtTop10Filter"); - case xlsb_type::BrtDynamicFilter: - return fmt::format_to(ctx.out(), "BrtDynamicFilter"); - case xlsb_type::BrtBeginCustomFilters: - return fmt::format_to(ctx.out(), "BrtBeginCustomFilters"); - case xlsb_type::BrtEndCustomFilters: - return fmt::format_to(ctx.out(), "BrtEndCustomFilters"); - case xlsb_type::BrtCustomFilter: - return fmt::format_to(ctx.out(), "BrtCustomFilter"); - case xlsb_type::BrtAFilterDateGroupItem: - return fmt::format_to(ctx.out(), "BrtAFilterDateGroupItem"); - case xlsb_type::BrtMergeCell: - return fmt::format_to(ctx.out(), "BrtMergeCell"); - case xlsb_type::BrtBeginMergeCells: - return fmt::format_to(ctx.out(), "BrtBeginMergeCells"); - case xlsb_type::BrtEndMergeCells: - return fmt::format_to(ctx.out(), "BrtEndMergeCells"); - case xlsb_type::BrtBeginPivotCacheDef: - return fmt::format_to(ctx.out(), "BrtBeginPivotCacheDef"); - case xlsb_type::BrtEndPivotCacheDef: - return fmt::format_to(ctx.out(), "BrtEndPivotCacheDef"); - case xlsb_type::BrtBeginPCDFields: - return fmt::format_to(ctx.out(), "BrtBeginPCDFields"); - case xlsb_type::BrtEndPCDFields: - return fmt::format_to(ctx.out(), "BrtEndPCDFields"); - case xlsb_type::BrtBeginPCDField: - return fmt::format_to(ctx.out(), "BrtBeginPCDField"); - case xlsb_type::BrtEndPCDField: - return fmt::format_to(ctx.out(), "BrtEndPCDField"); - case xlsb_type::BrtBeginPCDSource: - return fmt::format_to(ctx.out(), "BrtBeginPCDSource"); - case xlsb_type::BrtEndPCDSource: - return fmt::format_to(ctx.out(), "BrtEndPCDSource"); - case xlsb_type::BrtBeginPCDSRange: - return fmt::format_to(ctx.out(), "BrtBeginPCDSRange"); - case xlsb_type::BrtEndPCDSRange: - return fmt::format_to(ctx.out(), "BrtEndPCDSRange"); - case xlsb_type::BrtBeginPCDFAtbl: - return fmt::format_to(ctx.out(), "BrtBeginPCDFAtbl"); - case xlsb_type::BrtEndPCDFAtbl: - return fmt::format_to(ctx.out(), "BrtEndPCDFAtbl"); - case xlsb_type::BrtBeginPCDIRun: - return fmt::format_to(ctx.out(), "BrtBeginPCDIRun"); - case xlsb_type::BrtEndPCDIRun: - return fmt::format_to(ctx.out(), "BrtEndPCDIRun"); - case xlsb_type::BrtBeginPivotCacheRecords: - return fmt::format_to(ctx.out(), "BrtBeginPivotCacheRecords"); - case xlsb_type::BrtEndPivotCacheRecords: - return fmt::format_to(ctx.out(), "BrtEndPivotCacheRecords"); - case xlsb_type::BrtBeginPCDHierarchies: - return fmt::format_to(ctx.out(), "BrtBeginPCDHierarchies"); - case xlsb_type::BrtEndPCDHierarchies: - return fmt::format_to(ctx.out(), "BrtEndPCDHierarchies"); - case xlsb_type::BrtBeginPCDHierarchy: - return fmt::format_to(ctx.out(), "BrtBeginPCDHierarchy"); - case xlsb_type::BrtEndPCDHierarchy: - return fmt::format_to(ctx.out(), "BrtEndPCDHierarchy"); - case xlsb_type::BrtBeginPCDHFieldsUsage: - return fmt::format_to(ctx.out(), "BrtBeginPCDHFieldsUsage"); - case xlsb_type::BrtEndPCDHFieldsUsage: - return fmt::format_to(ctx.out(), "BrtEndPCDHFieldsUsage"); - case xlsb_type::BrtBeginExtConnection: - return fmt::format_to(ctx.out(), "BrtBeginExtConnection"); - case xlsb_type::BrtEndExtConnection: - return fmt::format_to(ctx.out(), "BrtEndExtConnection"); - case xlsb_type::BrtBeginECDbProps: - return fmt::format_to(ctx.out(), "BrtBeginECDbProps"); - case xlsb_type::BrtEndECDbProps: - return fmt::format_to(ctx.out(), "BrtEndECDbProps"); - case xlsb_type::BrtBeginECOlapProps: - return fmt::format_to(ctx.out(), "BrtBeginECOlapProps"); - case xlsb_type::BrtEndECOlapProps: - return fmt::format_to(ctx.out(), "BrtEndECOlapProps"); - case xlsb_type::BrtBeginPCDSConsol: - return fmt::format_to(ctx.out(), "BrtBeginPCDSConsol"); - case xlsb_type::BrtEndPCDSConsol: - return fmt::format_to(ctx.out(), "BrtEndPCDSConsol"); - case xlsb_type::BrtBeginPCDSCPages: - return fmt::format_to(ctx.out(), "BrtBeginPCDSCPages"); - case xlsb_type::BrtEndPCDSCPages: - return fmt::format_to(ctx.out(), "BrtEndPCDSCPages"); - case xlsb_type::BrtBeginPCDSCPage: - return fmt::format_to(ctx.out(), "BrtBeginPCDSCPage"); - case xlsb_type::BrtEndPCDSCPage: - return fmt::format_to(ctx.out(), "BrtEndPCDSCPage"); - case xlsb_type::BrtBeginPCDSCPItem: - return fmt::format_to(ctx.out(), "BrtBeginPCDSCPItem"); - case xlsb_type::BrtEndPCDSCPItem: - return fmt::format_to(ctx.out(), "BrtEndPCDSCPItem"); - case xlsb_type::BrtBeginPCDSCSets: - return fmt::format_to(ctx.out(), "BrtBeginPCDSCSets"); - case xlsb_type::BrtEndPCDSCSets: - return fmt::format_to(ctx.out(), "BrtEndPCDSCSets"); - case xlsb_type::BrtBeginPCDSCSet: - return fmt::format_to(ctx.out(), "BrtBeginPCDSCSet"); - case xlsb_type::BrtEndPCDSCSet: - return fmt::format_to(ctx.out(), "BrtEndPCDSCSet"); - case xlsb_type::BrtBeginPCDFGroup: - return fmt::format_to(ctx.out(), "BrtBeginPCDFGroup"); - case xlsb_type::BrtEndPCDFGroup: - return fmt::format_to(ctx.out(), "BrtEndPCDFGroup"); - case xlsb_type::BrtBeginPCDFGItems: - return fmt::format_to(ctx.out(), "BrtBeginPCDFGItems"); - case xlsb_type::BrtEndPCDFGItems: - return fmt::format_to(ctx.out(), "BrtEndPCDFGItems"); - case xlsb_type::BrtBeginPCDFGRange: - return fmt::format_to(ctx.out(), "BrtBeginPCDFGRange"); - case xlsb_type::BrtEndPCDFGRange: - return fmt::format_to(ctx.out(), "BrtEndPCDFGRange"); - case xlsb_type::BrtBeginPCDFGDiscrete: - return fmt::format_to(ctx.out(), "BrtBeginPCDFGDiscrete"); - case xlsb_type::BrtEndPCDFGDiscrete: - return fmt::format_to(ctx.out(), "BrtEndPCDFGDiscrete"); - case xlsb_type::BrtBeginPCDSDTupleCache: - return fmt::format_to(ctx.out(), "BrtBeginPCDSDTupleCache"); - case xlsb_type::BrtEndPCDSDTupleCache: - return fmt::format_to(ctx.out(), "BrtEndPCDSDTupleCache"); - case xlsb_type::BrtBeginPCDSDTCEntries: - return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCEntries"); - case xlsb_type::BrtEndPCDSDTCEntries: - return fmt::format_to(ctx.out(), "BrtEndPCDSDTCEntries"); - case xlsb_type::BrtBeginPCDSDTCEMembers: - return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCEMembers"); - case xlsb_type::BrtEndPCDSDTCEMembers: - return fmt::format_to(ctx.out(), "BrtEndPCDSDTCEMembers"); - case xlsb_type::BrtBeginPCDSDTCEMember: - return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCEMember"); - case xlsb_type::BrtEndPCDSDTCEMember: - return fmt::format_to(ctx.out(), "BrtEndPCDSDTCEMember"); - case xlsb_type::BrtBeginPCDSDTCQueries: - return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCQueries"); - case xlsb_type::BrtEndPCDSDTCQueries: - return fmt::format_to(ctx.out(), "BrtEndPCDSDTCQueries"); - case xlsb_type::BrtBeginPCDSDTCQuery: - return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCQuery"); - case xlsb_type::BrtEndPCDSDTCQuery: - return fmt::format_to(ctx.out(), "BrtEndPCDSDTCQuery"); - case xlsb_type::BrtBeginPCDSDTCSets: - return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCSets"); - case xlsb_type::BrtEndPCDSDTCSets: - return fmt::format_to(ctx.out(), "BrtEndPCDSDTCSets"); - case xlsb_type::BrtBeginPCDSDTCSet: - return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCSet"); - case xlsb_type::BrtEndPCDSDTCSet: - return fmt::format_to(ctx.out(), "BrtEndPCDSDTCSet"); - case xlsb_type::BrtBeginPCDCalcItems: - return fmt::format_to(ctx.out(), "BrtBeginPCDCalcItems"); - case xlsb_type::BrtEndPCDCalcItems: - return fmt::format_to(ctx.out(), "BrtEndPCDCalcItems"); - case xlsb_type::BrtBeginPCDCalcItem: - return fmt::format_to(ctx.out(), "BrtBeginPCDCalcItem"); - case xlsb_type::BrtEndPCDCalcItem: - return fmt::format_to(ctx.out(), "BrtEndPCDCalcItem"); - case xlsb_type::BrtBeginPRule: - return fmt::format_to(ctx.out(), "BrtBeginPRule"); - case xlsb_type::BrtEndPRule: - return fmt::format_to(ctx.out(), "BrtEndPRule"); - case xlsb_type::BrtBeginPRFilters: - return fmt::format_to(ctx.out(), "BrtBeginPRFilters"); - case xlsb_type::BrtEndPRFilters: - return fmt::format_to(ctx.out(), "BrtEndPRFilters"); - case xlsb_type::BrtBeginPRFilter: - return fmt::format_to(ctx.out(), "BrtBeginPRFilter"); - case xlsb_type::BrtEndPRFilter: - return fmt::format_to(ctx.out(), "BrtEndPRFilter"); - case xlsb_type::BrtBeginPNames: - return fmt::format_to(ctx.out(), "BrtBeginPNames"); - case xlsb_type::BrtEndPNames: - return fmt::format_to(ctx.out(), "BrtEndPNames"); - case xlsb_type::BrtBeginPName: - return fmt::format_to(ctx.out(), "BrtBeginPName"); - case xlsb_type::BrtEndPName: - return fmt::format_to(ctx.out(), "BrtEndPName"); - case xlsb_type::BrtBeginPNPairs: - return fmt::format_to(ctx.out(), "BrtBeginPNPairs"); - case xlsb_type::BrtEndPNPairs: - return fmt::format_to(ctx.out(), "BrtEndPNPairs"); - case xlsb_type::BrtBeginPNPair: - return fmt::format_to(ctx.out(), "BrtBeginPNPair"); - case xlsb_type::BrtEndPNPair: - return fmt::format_to(ctx.out(), "BrtEndPNPair"); - case xlsb_type::BrtBeginECWebProps: - return fmt::format_to(ctx.out(), "BrtBeginECWebProps"); - case xlsb_type::BrtEndECWebProps: - return fmt::format_to(ctx.out(), "BrtEndECWebProps"); - case xlsb_type::BrtBeginEcWpTables: - return fmt::format_to(ctx.out(), "BrtBeginEcWpTables"); - case xlsb_type::BrtEndECWPTables: - return fmt::format_to(ctx.out(), "BrtEndECWPTables"); - case xlsb_type::BrtBeginECParams: - return fmt::format_to(ctx.out(), "BrtBeginECParams"); - case xlsb_type::BrtEndECParams: - return fmt::format_to(ctx.out(), "BrtEndECParams"); - case xlsb_type::BrtBeginECParam: - return fmt::format_to(ctx.out(), "BrtBeginECParam"); - case xlsb_type::BrtEndECParam: - return fmt::format_to(ctx.out(), "BrtEndECParam"); - case xlsb_type::BrtBeginPCDKPIs: - return fmt::format_to(ctx.out(), "BrtBeginPCDKPIs"); - case xlsb_type::BrtEndPCDKPIs: - return fmt::format_to(ctx.out(), "BrtEndPCDKPIs"); - case xlsb_type::BrtBeginPCDKPI: - return fmt::format_to(ctx.out(), "BrtBeginPCDKPI"); - case xlsb_type::BrtEndPCDKPI: - return fmt::format_to(ctx.out(), "BrtEndPCDKPI"); - case xlsb_type::BrtBeginDims: - return fmt::format_to(ctx.out(), "BrtBeginDims"); - case xlsb_type::BrtEndDims: - return fmt::format_to(ctx.out(), "BrtEndDims"); - case xlsb_type::BrtBeginDim: - return fmt::format_to(ctx.out(), "BrtBeginDim"); - case xlsb_type::BrtEndDim: - return fmt::format_to(ctx.out(), "BrtEndDim"); - case xlsb_type::BrtIndexPartEnd: - return fmt::format_to(ctx.out(), "BrtIndexPartEnd"); - case xlsb_type::BrtBeginStyleSheet: - return fmt::format_to(ctx.out(), "BrtBeginStyleSheet"); - case xlsb_type::BrtEndStyleSheet: - return fmt::format_to(ctx.out(), "BrtEndStyleSheet"); - case xlsb_type::BrtBeginSXView: - return fmt::format_to(ctx.out(), "BrtBeginSXView"); - case xlsb_type::BrtEndSXVI: - return fmt::format_to(ctx.out(), "BrtEndSXVI"); - case xlsb_type::BrtBeginSXVI: - return fmt::format_to(ctx.out(), "BrtBeginSXVI"); - case xlsb_type::BrtBeginSXVIs: - return fmt::format_to(ctx.out(), "BrtBeginSXVIs"); - case xlsb_type::BrtEndSXVIs: - return fmt::format_to(ctx.out(), "BrtEndSXVIs"); - case xlsb_type::BrtBeginSXVD: - return fmt::format_to(ctx.out(), "BrtBeginSXVD"); - case xlsb_type::BrtEndSXVD: - return fmt::format_to(ctx.out(), "BrtEndSXVD"); - case xlsb_type::BrtBeginSXVDs: - return fmt::format_to(ctx.out(), "BrtBeginSXVDs"); - case xlsb_type::BrtEndSXVDs: - return fmt::format_to(ctx.out(), "BrtEndSXVDs"); - case xlsb_type::BrtBeginSXPI: - return fmt::format_to(ctx.out(), "BrtBeginSXPI"); - case xlsb_type::BrtEndSXPI: - return fmt::format_to(ctx.out(), "BrtEndSXPI"); - case xlsb_type::BrtBeginSXPIs: - return fmt::format_to(ctx.out(), "BrtBeginSXPIs"); - case xlsb_type::BrtEndSXPIs: - return fmt::format_to(ctx.out(), "BrtEndSXPIs"); - case xlsb_type::BrtBeginSXDI: - return fmt::format_to(ctx.out(), "BrtBeginSXDI"); - case xlsb_type::BrtEndSXDI: - return fmt::format_to(ctx.out(), "BrtEndSXDI"); - case xlsb_type::BrtBeginSXDIs: - return fmt::format_to(ctx.out(), "BrtBeginSXDIs"); - case xlsb_type::BrtEndSXDIs: - return fmt::format_to(ctx.out(), "BrtEndSXDIs"); - case xlsb_type::BrtBeginSXLI: - return fmt::format_to(ctx.out(), "BrtBeginSXLI"); - case xlsb_type::BrtEndSXLI: - return fmt::format_to(ctx.out(), "BrtEndSXLI"); - case xlsb_type::BrtBeginSXLIRws: - return fmt::format_to(ctx.out(), "BrtBeginSXLIRws"); - case xlsb_type::BrtEndSXLIRws: - return fmt::format_to(ctx.out(), "BrtEndSXLIRws"); - case xlsb_type::BrtBeginSXLICols: - return fmt::format_to(ctx.out(), "BrtBeginSXLICols"); - case xlsb_type::BrtEndSXLICols: - return fmt::format_to(ctx.out(), "BrtEndSXLICols"); - case xlsb_type::BrtBeginSXFormat: - return fmt::format_to(ctx.out(), "BrtBeginSXFormat"); - case xlsb_type::BrtEndSXFormat: - return fmt::format_to(ctx.out(), "BrtEndSXFormat"); - case xlsb_type::BrtBeginSXFormats: - return fmt::format_to(ctx.out(), "BrtBeginSXFormats"); - case xlsb_type::BrtEndSxFormats: - return fmt::format_to(ctx.out(), "BrtEndSxFormats"); - case xlsb_type::BrtBeginSxSelect: - return fmt::format_to(ctx.out(), "BrtBeginSxSelect"); - case xlsb_type::BrtEndSxSelect: - return fmt::format_to(ctx.out(), "BrtEndSxSelect"); - case xlsb_type::BrtBeginISXVDRws: - return fmt::format_to(ctx.out(), "BrtBeginISXVDRws"); - case xlsb_type::BrtEndISXVDRws: - return fmt::format_to(ctx.out(), "BrtEndISXVDRws"); - case xlsb_type::BrtBeginISXVDCols: - return fmt::format_to(ctx.out(), "BrtBeginISXVDCols"); - case xlsb_type::BrtEndISXVDCols: - return fmt::format_to(ctx.out(), "BrtEndISXVDCols"); - case xlsb_type::BrtEndSXLocation: - return fmt::format_to(ctx.out(), "BrtEndSXLocation"); - case xlsb_type::BrtBeginSXLocation: - return fmt::format_to(ctx.out(), "BrtBeginSXLocation"); - case xlsb_type::BrtEndSXView: - return fmt::format_to(ctx.out(), "BrtEndSXView"); - case xlsb_type::BrtBeginSXTHs: - return fmt::format_to(ctx.out(), "BrtBeginSXTHs"); - case xlsb_type::BrtEndSXTHs: - return fmt::format_to(ctx.out(), "BrtEndSXTHs"); - case xlsb_type::BrtBeginSXTH: - return fmt::format_to(ctx.out(), "BrtBeginSXTH"); - case xlsb_type::BrtEndSXTH: - return fmt::format_to(ctx.out(), "BrtEndSXTH"); - case xlsb_type::BrtBeginISXTHRws: - return fmt::format_to(ctx.out(), "BrtBeginISXTHRws"); - case xlsb_type::BrtEndISXTHRws: - return fmt::format_to(ctx.out(), "BrtEndISXTHRws"); - case xlsb_type::BrtBeginISXTHCols: - return fmt::format_to(ctx.out(), "BrtBeginISXTHCols"); - case xlsb_type::BrtEndISXTHCols: - return fmt::format_to(ctx.out(), "BrtEndISXTHCols"); - case xlsb_type::BrtBeginSXTDMPS: - return fmt::format_to(ctx.out(), "BrtBeginSXTDMPS"); - case xlsb_type::BrtEndSXTDMPs: - return fmt::format_to(ctx.out(), "BrtEndSXTDMPs"); - case xlsb_type::BrtBeginSXTDMP: - return fmt::format_to(ctx.out(), "BrtBeginSXTDMP"); - case xlsb_type::BrtEndSXTDMP: - return fmt::format_to(ctx.out(), "BrtEndSXTDMP"); - case xlsb_type::BrtBeginSXTHItems: - return fmt::format_to(ctx.out(), "BrtBeginSXTHItems"); - case xlsb_type::BrtEndSXTHItems: - return fmt::format_to(ctx.out(), "BrtEndSXTHItems"); - case xlsb_type::BrtBeginSXTHItem: - return fmt::format_to(ctx.out(), "BrtBeginSXTHItem"); - case xlsb_type::BrtEndSXTHItem: - return fmt::format_to(ctx.out(), "BrtEndSXTHItem"); - case xlsb_type::BrtBeginMetadata: - return fmt::format_to(ctx.out(), "BrtBeginMetadata"); - case xlsb_type::BrtEndMetadata: - return fmt::format_to(ctx.out(), "BrtEndMetadata"); - case xlsb_type::BrtBeginEsmdtinfo: - return fmt::format_to(ctx.out(), "BrtBeginEsmdtinfo"); - case xlsb_type::BrtMdtinfo: - return fmt::format_to(ctx.out(), "BrtMdtinfo"); - case xlsb_type::BrtEndEsmdtinfo: - return fmt::format_to(ctx.out(), "BrtEndEsmdtinfo"); - case xlsb_type::BrtBeginEsmdb: - return fmt::format_to(ctx.out(), "BrtBeginEsmdb"); - case xlsb_type::BrtEndEsmdb: - return fmt::format_to(ctx.out(), "BrtEndEsmdb"); - case xlsb_type::BrtBeginEsfmd: - return fmt::format_to(ctx.out(), "BrtBeginEsfmd"); - case xlsb_type::BrtEndEsfmd: - return fmt::format_to(ctx.out(), "BrtEndEsfmd"); - case xlsb_type::BrtBeginSingleCells: - return fmt::format_to(ctx.out(), "BrtBeginSingleCells"); - case xlsb_type::BrtEndSingleCells: - return fmt::format_to(ctx.out(), "BrtEndSingleCells"); - case xlsb_type::BrtBeginList: - return fmt::format_to(ctx.out(), "BrtBeginList"); - case xlsb_type::BrtEndList: - return fmt::format_to(ctx.out(), "BrtEndList"); - case xlsb_type::BrtBeginListCols: - return fmt::format_to(ctx.out(), "BrtBeginListCols"); - case xlsb_type::BrtEndListCols: - return fmt::format_to(ctx.out(), "BrtEndListCols"); - case xlsb_type::BrtBeginListCol: - return fmt::format_to(ctx.out(), "BrtBeginListCol"); - case xlsb_type::BrtEndListCol: - return fmt::format_to(ctx.out(), "BrtEndListCol"); - case xlsb_type::BrtBeginListXmlCPr: - return fmt::format_to(ctx.out(), "BrtBeginListXmlCPr"); - case xlsb_type::BrtEndListXmlCPr: - return fmt::format_to(ctx.out(), "BrtEndListXmlCPr"); - case xlsb_type::BrtListCCFmla: - return fmt::format_to(ctx.out(), "BrtListCCFmla"); - case xlsb_type::BrtListTrFmla: - return fmt::format_to(ctx.out(), "BrtListTrFmla"); - case xlsb_type::BrtBeginExternals: - return fmt::format_to(ctx.out(), "BrtBeginExternals"); - case xlsb_type::BrtEndExternals: - return fmt::format_to(ctx.out(), "BrtEndExternals"); - case xlsb_type::BrtSupBookSrc: - return fmt::format_to(ctx.out(), "BrtSupBookSrc"); - case xlsb_type::BrtSupSelf: - return fmt::format_to(ctx.out(), "BrtSupSelf"); - case xlsb_type::BrtSupSame: - return fmt::format_to(ctx.out(), "BrtSupSame"); - case xlsb_type::BrtSupTabs: - return fmt::format_to(ctx.out(), "BrtSupTabs"); - case xlsb_type::BrtBeginSupBook: - return fmt::format_to(ctx.out(), "BrtBeginSupBook"); - case xlsb_type::BrtPlaceholderName: - return fmt::format_to(ctx.out(), "BrtPlaceholderName"); - case xlsb_type::BrtExternSheet: - return fmt::format_to(ctx.out(), "BrtExternSheet"); - case xlsb_type::BrtExternTableStart: - return fmt::format_to(ctx.out(), "BrtExternTableStart"); - case xlsb_type::BrtExternTableEnd: - return fmt::format_to(ctx.out(), "BrtExternTableEnd"); - case xlsb_type::BrtExternRowHdr: - return fmt::format_to(ctx.out(), "BrtExternRowHdr"); - case xlsb_type::BrtExternCellBlank: - return fmt::format_to(ctx.out(), "BrtExternCellBlank"); - case xlsb_type::BrtExternCellReal: - return fmt::format_to(ctx.out(), "BrtExternCellReal"); - case xlsb_type::BrtExternCellBool: - return fmt::format_to(ctx.out(), "BrtExternCellBool"); - case xlsb_type::BrtExternCellError: - return fmt::format_to(ctx.out(), "BrtExternCellError"); - case xlsb_type::BrtExternCellString: - return fmt::format_to(ctx.out(), "BrtExternCellString"); - case xlsb_type::BrtBeginEsmdx: - return fmt::format_to(ctx.out(), "BrtBeginEsmdx"); - case xlsb_type::BrtEndEsmdx: - return fmt::format_to(ctx.out(), "BrtEndEsmdx"); - case xlsb_type::BrtBeginMdxSet: - return fmt::format_to(ctx.out(), "BrtBeginMdxSet"); - case xlsb_type::BrtEndMdxSet: - return fmt::format_to(ctx.out(), "BrtEndMdxSet"); - case xlsb_type::BrtBeginMdxMbrProp: - return fmt::format_to(ctx.out(), "BrtBeginMdxMbrProp"); - case xlsb_type::BrtEndMdxMbrProp: - return fmt::format_to(ctx.out(), "BrtEndMdxMbrProp"); - case xlsb_type::BrtBeginMdxKPI: - return fmt::format_to(ctx.out(), "BrtBeginMdxKPI"); - case xlsb_type::BrtEndMdxKPI: - return fmt::format_to(ctx.out(), "BrtEndMdxKPI"); - case xlsb_type::BrtBeginEsstr: - return fmt::format_to(ctx.out(), "BrtBeginEsstr"); - case xlsb_type::BrtEndEsstr: - return fmt::format_to(ctx.out(), "BrtEndEsstr"); - case xlsb_type::BrtBeginPRFItem: - return fmt::format_to(ctx.out(), "BrtBeginPRFItem"); - case xlsb_type::BrtEndPRFItem: - return fmt::format_to(ctx.out(), "BrtEndPRFItem"); - case xlsb_type::BrtBeginPivotCacheIDs: - return fmt::format_to(ctx.out(), "BrtBeginPivotCacheIDs"); - case xlsb_type::BrtEndPivotCacheIDs: - return fmt::format_to(ctx.out(), "BrtEndPivotCacheIDs"); - case xlsb_type::BrtBeginPivotCacheID: - return fmt::format_to(ctx.out(), "BrtBeginPivotCacheID"); - case xlsb_type::BrtEndPivotCacheID: - return fmt::format_to(ctx.out(), "BrtEndPivotCacheID"); - case xlsb_type::BrtBeginISXVIs: - return fmt::format_to(ctx.out(), "BrtBeginISXVIs"); - case xlsb_type::BrtEndISXVIs: - return fmt::format_to(ctx.out(), "BrtEndISXVIs"); - case xlsb_type::BrtBeginColInfos: - return fmt::format_to(ctx.out(), "BrtBeginColInfos"); - case xlsb_type::BrtEndColInfos: - return fmt::format_to(ctx.out(), "BrtEndColInfos"); - case xlsb_type::BrtBeginRwBrk: - return fmt::format_to(ctx.out(), "BrtBeginRwBrk"); - case xlsb_type::BrtEndRwBrk: - return fmt::format_to(ctx.out(), "BrtEndRwBrk"); - case xlsb_type::BrtBeginColBrk: - return fmt::format_to(ctx.out(), "BrtBeginColBrk"); - case xlsb_type::BrtEndColBrk: - return fmt::format_to(ctx.out(), "BrtEndColBrk"); - case xlsb_type::BrtBrk: - return fmt::format_to(ctx.out(), "BrtBrk"); - case xlsb_type::BrtUserBookView: - return fmt::format_to(ctx.out(), "BrtUserBookView"); - case xlsb_type::BrtInfo: - return fmt::format_to(ctx.out(), "BrtInfo"); - case xlsb_type::BrtCUsr: - return fmt::format_to(ctx.out(), "BrtCUsr"); - case xlsb_type::BrtUsr: - return fmt::format_to(ctx.out(), "BrtUsr"); - case xlsb_type::BrtBeginUsers: - return fmt::format_to(ctx.out(), "BrtBeginUsers"); - case xlsb_type::BrtEOF: - return fmt::format_to(ctx.out(), "BrtEOF"); - case xlsb_type::BrtUCR: - return fmt::format_to(ctx.out(), "BrtUCR"); - case xlsb_type::BrtRRInsDel: - return fmt::format_to(ctx.out(), "BrtRRInsDel"); - case xlsb_type::BrtRREndInsDel: - return fmt::format_to(ctx.out(), "BrtRREndInsDel"); - case xlsb_type::BrtRRMove: - return fmt::format_to(ctx.out(), "BrtRRMove"); - case xlsb_type::BrtRREndMove: - return fmt::format_to(ctx.out(), "BrtRREndMove"); - case xlsb_type::BrtRRChgCell: - return fmt::format_to(ctx.out(), "BrtRRChgCell"); - case xlsb_type::BrtRREndChgCell: - return fmt::format_to(ctx.out(), "BrtRREndChgCell"); - case xlsb_type::BrtRRHeader: - return fmt::format_to(ctx.out(), "BrtRRHeader"); - case xlsb_type::BrtRRUserView: - return fmt::format_to(ctx.out(), "BrtRRUserView"); - case xlsb_type::BrtRRRenSheet: - return fmt::format_to(ctx.out(), "BrtRRRenSheet"); - case xlsb_type::BrtRRInsertSh: - return fmt::format_to(ctx.out(), "BrtRRInsertSh"); - case xlsb_type::BrtRRDefName: - return fmt::format_to(ctx.out(), "BrtRRDefName"); - case xlsb_type::BrtRRNote: - return fmt::format_to(ctx.out(), "BrtRRNote"); - case xlsb_type::BrtRRConflict: - return fmt::format_to(ctx.out(), "BrtRRConflict"); - case xlsb_type::BrtRRTQSIF: - return fmt::format_to(ctx.out(), "BrtRRTQSIF"); - case xlsb_type::BrtRRFormat: - return fmt::format_to(ctx.out(), "BrtRRFormat"); - case xlsb_type::BrtRREndFormat: - return fmt::format_to(ctx.out(), "BrtRREndFormat"); - case xlsb_type::BrtRRAutoFmt: - return fmt::format_to(ctx.out(), "BrtRRAutoFmt"); - case xlsb_type::BrtBeginUserShViews: - return fmt::format_to(ctx.out(), "BrtBeginUserShViews"); - case xlsb_type::BrtBeginUserShView: - return fmt::format_to(ctx.out(), "BrtBeginUserShView"); - case xlsb_type::BrtEndUserShView: - return fmt::format_to(ctx.out(), "BrtEndUserShView"); - case xlsb_type::BrtEndUserShViews: - return fmt::format_to(ctx.out(), "BrtEndUserShViews"); - case xlsb_type::BrtArrFmla: - return fmt::format_to(ctx.out(), "BrtArrFmla"); - case xlsb_type::BrtShrFmla: - return fmt::format_to(ctx.out(), "BrtShrFmla"); - case xlsb_type::BrtTable: - return fmt::format_to(ctx.out(), "BrtTable"); - case xlsb_type::BrtBeginExtConnections: - return fmt::format_to(ctx.out(), "BrtBeginExtConnections"); - case xlsb_type::BrtEndExtConnections: - return fmt::format_to(ctx.out(), "BrtEndExtConnections"); - case xlsb_type::BrtBeginPCDCalcMems: - return fmt::format_to(ctx.out(), "BrtBeginPCDCalcMems"); - case xlsb_type::BrtEndPCDCalcMems: - return fmt::format_to(ctx.out(), "BrtEndPCDCalcMems"); - case xlsb_type::BrtBeginPCDCalcMem: - return fmt::format_to(ctx.out(), "BrtBeginPCDCalcMem"); - case xlsb_type::BrtEndPCDCalcMem: - return fmt::format_to(ctx.out(), "BrtEndPCDCalcMem"); - case xlsb_type::BrtBeginPCDHGLevels: - return fmt::format_to(ctx.out(), "BrtBeginPCDHGLevels"); - case xlsb_type::BrtEndPCDHGLevels: - return fmt::format_to(ctx.out(), "BrtEndPCDHGLevels"); - case xlsb_type::BrtBeginPCDHGLevel: - return fmt::format_to(ctx.out(), "BrtBeginPCDHGLevel"); - case xlsb_type::BrtEndPCDHGLevel: - return fmt::format_to(ctx.out(), "BrtEndPCDHGLevel"); - case xlsb_type::BrtBeginPCDHGLGroups: - return fmt::format_to(ctx.out(), "BrtBeginPCDHGLGroups"); - case xlsb_type::BrtEndPCDHGLGroups: - return fmt::format_to(ctx.out(), "BrtEndPCDHGLGroups"); - case xlsb_type::BrtBeginPCDHGLGroup: - return fmt::format_to(ctx.out(), "BrtBeginPCDHGLGroup"); - case xlsb_type::BrtEndPCDHGLGroup: - return fmt::format_to(ctx.out(), "BrtEndPCDHGLGroup"); - case xlsb_type::BrtBeginPCDHGLGMembers: - return fmt::format_to(ctx.out(), "BrtBeginPCDHGLGMembers"); - case xlsb_type::BrtEndPCDHGLGMembers: - return fmt::format_to(ctx.out(), "BrtEndPCDHGLGMembers"); - case xlsb_type::BrtBeginPCDHGLGMember: - return fmt::format_to(ctx.out(), "BrtBeginPCDHGLGMember"); - case xlsb_type::BrtEndPCDHGLGMember: - return fmt::format_to(ctx.out(), "BrtEndPCDHGLGMember"); - case xlsb_type::BrtBeginQSI: - return fmt::format_to(ctx.out(), "BrtBeginQSI"); - case xlsb_type::BrtEndQSI: - return fmt::format_to(ctx.out(), "BrtEndQSI"); - case xlsb_type::BrtBeginQSIR: - return fmt::format_to(ctx.out(), "BrtBeginQSIR"); - case xlsb_type::BrtEndQSIR: - return fmt::format_to(ctx.out(), "BrtEndQSIR"); - case xlsb_type::BrtBeginDeletedNames: - return fmt::format_to(ctx.out(), "BrtBeginDeletedNames"); - case xlsb_type::BrtEndDeletedNames: - return fmt::format_to(ctx.out(), "BrtEndDeletedNames"); - case xlsb_type::BrtBeginDeletedName: - return fmt::format_to(ctx.out(), "BrtBeginDeletedName"); - case xlsb_type::BrtEndDeletedName: - return fmt::format_to(ctx.out(), "BrtEndDeletedName"); - case xlsb_type::BrtBeginQSIFs: - return fmt::format_to(ctx.out(), "BrtBeginQSIFs"); - case xlsb_type::BrtEndQSIFs: - return fmt::format_to(ctx.out(), "BrtEndQSIFs"); - case xlsb_type::BrtBeginQSIF: - return fmt::format_to(ctx.out(), "BrtBeginQSIF"); - case xlsb_type::BrtEndQSIF: - return fmt::format_to(ctx.out(), "BrtEndQSIF"); - case xlsb_type::BrtBeginAutoSortScope: - return fmt::format_to(ctx.out(), "BrtBeginAutoSortScope"); - case xlsb_type::BrtEndAutoSortScope: - return fmt::format_to(ctx.out(), "BrtEndAutoSortScope"); - case xlsb_type::BrtBeginConditionalFormatting: - return fmt::format_to(ctx.out(), "BrtBeginConditionalFormatting"); - case xlsb_type::BrtEndConditionalFormatting: - return fmt::format_to(ctx.out(), "BrtEndConditionalFormatting"); - case xlsb_type::BrtBeginCFRule: - return fmt::format_to(ctx.out(), "BrtBeginCFRule"); - case xlsb_type::BrtEndCFRule: - return fmt::format_to(ctx.out(), "BrtEndCFRule"); - case xlsb_type::BrtBeginIconSet: - return fmt::format_to(ctx.out(), "BrtBeginIconSet"); - case xlsb_type::BrtEndIconSet: - return fmt::format_to(ctx.out(), "BrtEndIconSet"); - case xlsb_type::BrtBeginDatabar: - return fmt::format_to(ctx.out(), "BrtBeginDatabar"); - case xlsb_type::BrtEndDatabar: - return fmt::format_to(ctx.out(), "BrtEndDatabar"); - case xlsb_type::BrtBeginColorScale: - return fmt::format_to(ctx.out(), "BrtBeginColorScale"); - case xlsb_type::BrtEndColorScale: - return fmt::format_to(ctx.out(), "BrtEndColorScale"); - case xlsb_type::BrtCFVO: - return fmt::format_to(ctx.out(), "BrtCFVO"); - case xlsb_type::BrtExternValueMeta: - return fmt::format_to(ctx.out(), "BrtExternValueMeta"); - case xlsb_type::BrtBeginColorPalette: - return fmt::format_to(ctx.out(), "BrtBeginColorPalette"); - case xlsb_type::BrtEndColorPalette: - return fmt::format_to(ctx.out(), "BrtEndColorPalette"); - case xlsb_type::BrtIndexedColor: - return fmt::format_to(ctx.out(), "BrtIndexedColor"); - case xlsb_type::BrtMargins: - return fmt::format_to(ctx.out(), "BrtMargins"); - case xlsb_type::BrtPrintOptions: - return fmt::format_to(ctx.out(), "BrtPrintOptions"); - case xlsb_type::BrtPageSetup: - return fmt::format_to(ctx.out(), "BrtPageSetup"); - case xlsb_type::BrtBeginHeaderFooter: - return fmt::format_to(ctx.out(), "BrtBeginHeaderFooter"); - case xlsb_type::BrtEndHeaderFooter: - return fmt::format_to(ctx.out(), "BrtEndHeaderFooter"); - case xlsb_type::BrtBeginSXCrtFormat: - return fmt::format_to(ctx.out(), "BrtBeginSXCrtFormat"); - case xlsb_type::BrtEndSXCrtFormat: - return fmt::format_to(ctx.out(), "BrtEndSXCrtFormat"); - case xlsb_type::BrtBeginSXCrtFormats: - return fmt::format_to(ctx.out(), "BrtBeginSXCrtFormats"); - case xlsb_type::BrtEndSXCrtFormats: - return fmt::format_to(ctx.out(), "BrtEndSXCrtFormats"); - case xlsb_type::BrtWsFmtInfo: - return fmt::format_to(ctx.out(), "BrtWsFmtInfo"); - case xlsb_type::BrtBeginMgs: - return fmt::format_to(ctx.out(), "BrtBeginMgs"); - case xlsb_type::BrtEndMGs: - return fmt::format_to(ctx.out(), "BrtEndMGs"); - case xlsb_type::BrtBeginMGMaps: - return fmt::format_to(ctx.out(), "BrtBeginMGMaps"); - case xlsb_type::BrtEndMGMaps: - return fmt::format_to(ctx.out(), "BrtEndMGMaps"); - case xlsb_type::BrtBeginMG: - return fmt::format_to(ctx.out(), "BrtBeginMG"); - case xlsb_type::BrtEndMG: - return fmt::format_to(ctx.out(), "BrtEndMG"); - case xlsb_type::BrtBeginMap: - return fmt::format_to(ctx.out(), "BrtBeginMap"); - case xlsb_type::BrtEndMap: - return fmt::format_to(ctx.out(), "BrtEndMap"); - case xlsb_type::BrtHLink: - return fmt::format_to(ctx.out(), "BrtHLink"); - case xlsb_type::BrtBeginDCon: - return fmt::format_to(ctx.out(), "BrtBeginDCon"); - case xlsb_type::BrtEndDCon: - return fmt::format_to(ctx.out(), "BrtEndDCon"); - case xlsb_type::BrtBeginDRefs: - return fmt::format_to(ctx.out(), "BrtBeginDRefs"); - case xlsb_type::BrtEndDRefs: - return fmt::format_to(ctx.out(), "BrtEndDRefs"); - case xlsb_type::BrtDRef: - return fmt::format_to(ctx.out(), "BrtDRef"); - case xlsb_type::BrtBeginScenMan: - return fmt::format_to(ctx.out(), "BrtBeginScenMan"); - case xlsb_type::BrtEndScenMan: - return fmt::format_to(ctx.out(), "BrtEndScenMan"); - case xlsb_type::BrtBeginSct: - return fmt::format_to(ctx.out(), "BrtBeginSct"); - case xlsb_type::BrtEndSct: - return fmt::format_to(ctx.out(), "BrtEndSct"); - case xlsb_type::BrtSlc: - return fmt::format_to(ctx.out(), "BrtSlc"); - case xlsb_type::BrtBeginDXFs: - return fmt::format_to(ctx.out(), "BrtBeginDXFs"); - case xlsb_type::BrtEndDXFs: - return fmt::format_to(ctx.out(), "BrtEndDXFs"); - case xlsb_type::BrtDXF: - return fmt::format_to(ctx.out(), "BrtDXF"); - case xlsb_type::BrtBeginTableStyles: - return fmt::format_to(ctx.out(), "BrtBeginTableStyles"); - case xlsb_type::BrtEndTableStyles: - return fmt::format_to(ctx.out(), "BrtEndTableStyles"); - case xlsb_type::BrtBeginTableStyle: - return fmt::format_to(ctx.out(), "BrtBeginTableStyle"); - case xlsb_type::BrtEndTableStyle: - return fmt::format_to(ctx.out(), "BrtEndTableStyle"); - case xlsb_type::BrtTableStyleElement: - return fmt::format_to(ctx.out(), "BrtTableStyleElement"); - case xlsb_type::BrtTableStyleClient: - return fmt::format_to(ctx.out(), "BrtTableStyleClient"); - case xlsb_type::BrtBeginVolDeps: - return fmt::format_to(ctx.out(), "BrtBeginVolDeps"); - case xlsb_type::BrtEndVolDeps: - return fmt::format_to(ctx.out(), "BrtEndVolDeps"); - case xlsb_type::BrtBeginVolType: - return fmt::format_to(ctx.out(), "BrtBeginVolType"); - case xlsb_type::BrtEndVolType: - return fmt::format_to(ctx.out(), "BrtEndVolType"); - case xlsb_type::BrtBeginVolMain: - return fmt::format_to(ctx.out(), "BrtBeginVolMain"); - case xlsb_type::BrtEndVolMain: - return fmt::format_to(ctx.out(), "BrtEndVolMain"); - case xlsb_type::BrtBeginVolTopic: - return fmt::format_to(ctx.out(), "BrtBeginVolTopic"); - case xlsb_type::BrtEndVolTopic: - return fmt::format_to(ctx.out(), "BrtEndVolTopic"); - case xlsb_type::BrtVolSubtopic: - return fmt::format_to(ctx.out(), "BrtVolSubtopic"); - case xlsb_type::BrtVolRef: - return fmt::format_to(ctx.out(), "BrtVolRef"); - case xlsb_type::BrtVolNum: - return fmt::format_to(ctx.out(), "BrtVolNum"); - case xlsb_type::BrtVolErr: - return fmt::format_to(ctx.out(), "BrtVolErr"); - case xlsb_type::BrtVolStr: - return fmt::format_to(ctx.out(), "BrtVolStr"); - case xlsb_type::BrtVolBool: - return fmt::format_to(ctx.out(), "BrtVolBool"); - case xlsb_type::BrtBeginSortState: - return fmt::format_to(ctx.out(), "BrtBeginSortState"); - case xlsb_type::BrtEndSortState: - return fmt::format_to(ctx.out(), "BrtEndSortState"); - case xlsb_type::BrtBeginSortCond: - return fmt::format_to(ctx.out(), "BrtBeginSortCond"); - case xlsb_type::BrtEndSortCond: - return fmt::format_to(ctx.out(), "BrtEndSortCond"); - case xlsb_type::BrtBookProtection: - return fmt::format_to(ctx.out(), "BrtBookProtection"); - case xlsb_type::BrtSheetProtection: - return fmt::format_to(ctx.out(), "BrtSheetProtection"); - case xlsb_type::BrtRangeProtection: - return fmt::format_to(ctx.out(), "BrtRangeProtection"); - case xlsb_type::BrtPhoneticInfo: - return fmt::format_to(ctx.out(), "BrtPhoneticInfo"); - case xlsb_type::BrtBeginECTxtWiz: - return fmt::format_to(ctx.out(), "BrtBeginECTxtWiz"); - case xlsb_type::BrtEndECTxtWiz: - return fmt::format_to(ctx.out(), "BrtEndECTxtWiz"); - case xlsb_type::BrtBeginECTWFldInfoLst: - return fmt::format_to(ctx.out(), "BrtBeginECTWFldInfoLst"); - case xlsb_type::BrtEndECTWFldInfoLst: - return fmt::format_to(ctx.out(), "BrtEndECTWFldInfoLst"); - case xlsb_type::BrtBeginECTwFldInfo: - return fmt::format_to(ctx.out(), "BrtBeginECTwFldInfo"); - case xlsb_type::BrtFileSharing: - return fmt::format_to(ctx.out(), "BrtFileSharing"); - case xlsb_type::BrtOleSize: - return fmt::format_to(ctx.out(), "BrtOleSize"); - case xlsb_type::BrtDrawing: - return fmt::format_to(ctx.out(), "BrtDrawing"); - case xlsb_type::BrtLegacyDrawing: - return fmt::format_to(ctx.out(), "BrtLegacyDrawing"); - case xlsb_type::BrtLegacyDrawingHF: - return fmt::format_to(ctx.out(), "BrtLegacyDrawingHF"); - case xlsb_type::BrtWebOpt: - return fmt::format_to(ctx.out(), "BrtWebOpt"); - case xlsb_type::BrtBeginWebPubItems: - return fmt::format_to(ctx.out(), "BrtBeginWebPubItems"); - case xlsb_type::BrtEndWebPubItems: - return fmt::format_to(ctx.out(), "BrtEndWebPubItems"); - case xlsb_type::BrtBeginWebPubItem: - return fmt::format_to(ctx.out(), "BrtBeginWebPubItem"); - case xlsb_type::BrtEndWebPubItem: - return fmt::format_to(ctx.out(), "BrtEndWebPubItem"); - case xlsb_type::BrtBeginSXCondFmt: - return fmt::format_to(ctx.out(), "BrtBeginSXCondFmt"); - case xlsb_type::BrtEndSXCondFmt: - return fmt::format_to(ctx.out(), "BrtEndSXCondFmt"); - case xlsb_type::BrtBeginSXCondFmts: - return fmt::format_to(ctx.out(), "BrtBeginSXCondFmts"); - case xlsb_type::BrtEndSXCondFmts: - return fmt::format_to(ctx.out(), "BrtEndSXCondFmts"); - case xlsb_type::BrtBkHim: - return fmt::format_to(ctx.out(), "BrtBkHim"); - case xlsb_type::BrtColor: - return fmt::format_to(ctx.out(), "BrtColor"); - case xlsb_type::BrtBeginIndexedColors: - return fmt::format_to(ctx.out(), "BrtBeginIndexedColors"); - case xlsb_type::BrtEndIndexedColors: - return fmt::format_to(ctx.out(), "BrtEndIndexedColors"); - case xlsb_type::BrtBeginMRUColors: - return fmt::format_to(ctx.out(), "BrtBeginMRUColors"); - case xlsb_type::BrtEndMRUColors: - return fmt::format_to(ctx.out(), "BrtEndMRUColors"); - case xlsb_type::BrtMRUColor: - return fmt::format_to(ctx.out(), "BrtMRUColor"); - case xlsb_type::BrtBeginDVals: - return fmt::format_to(ctx.out(), "BrtBeginDVals"); - case xlsb_type::BrtEndDVals: - return fmt::format_to(ctx.out(), "BrtEndDVals"); - case xlsb_type::BrtSupNameStart: - return fmt::format_to(ctx.out(), "BrtSupNameStart"); - case xlsb_type::BrtSupNameValueStart: - return fmt::format_to(ctx.out(), "BrtSupNameValueStart"); - case xlsb_type::BrtSupNameValueEnd: - return fmt::format_to(ctx.out(), "BrtSupNameValueEnd"); - case xlsb_type::BrtSupNameNum: - return fmt::format_to(ctx.out(), "BrtSupNameNum"); - case xlsb_type::BrtSupNameErr: - return fmt::format_to(ctx.out(), "BrtSupNameErr"); - case xlsb_type::BrtSupNameSt: - return fmt::format_to(ctx.out(), "BrtSupNameSt"); - case xlsb_type::BrtSupNameNil: - return fmt::format_to(ctx.out(), "BrtSupNameNil"); - case xlsb_type::BrtSupNameBool: - return fmt::format_to(ctx.out(), "BrtSupNameBool"); - case xlsb_type::BrtSupNameFmla: - return fmt::format_to(ctx.out(), "BrtSupNameFmla"); - case xlsb_type::BrtSupNameBits: - return fmt::format_to(ctx.out(), "BrtSupNameBits"); - case xlsb_type::BrtSupNameEnd: - return fmt::format_to(ctx.out(), "BrtSupNameEnd"); - case xlsb_type::BrtEndSupBook: - return fmt::format_to(ctx.out(), "BrtEndSupBook"); - case xlsb_type::BrtCellSmartTagProperty: - return fmt::format_to(ctx.out(), "BrtCellSmartTagProperty"); - case xlsb_type::BrtBeginCellSmartTag: - return fmt::format_to(ctx.out(), "BrtBeginCellSmartTag"); - case xlsb_type::BrtEndCellSmartTag: - return fmt::format_to(ctx.out(), "BrtEndCellSmartTag"); - case xlsb_type::BrtBeginCellSmartTags: - return fmt::format_to(ctx.out(), "BrtBeginCellSmartTags"); - case xlsb_type::BrtEndCellSmartTags: - return fmt::format_to(ctx.out(), "BrtEndCellSmartTags"); - case xlsb_type::BrtBeginSmartTags: - return fmt::format_to(ctx.out(), "BrtBeginSmartTags"); - case xlsb_type::BrtEndSmartTags: - return fmt::format_to(ctx.out(), "BrtEndSmartTags"); - case xlsb_type::BrtSmartTagType: - return fmt::format_to(ctx.out(), "BrtSmartTagType"); - case xlsb_type::BrtBeginSmartTagTypes: - return fmt::format_to(ctx.out(), "BrtBeginSmartTagTypes"); - case xlsb_type::BrtEndSmartTagTypes: - return fmt::format_to(ctx.out(), "BrtEndSmartTagTypes"); - case xlsb_type::BrtBeginSXFilters: - return fmt::format_to(ctx.out(), "BrtBeginSXFilters"); - case xlsb_type::BrtEndSXFilters: - return fmt::format_to(ctx.out(), "BrtEndSXFilters"); - case xlsb_type::BrtBeginSXFILTER: - return fmt::format_to(ctx.out(), "BrtBeginSXFILTER"); - case xlsb_type::BrtEndSXFilter: - return fmt::format_to(ctx.out(), "BrtEndSXFilter"); - case xlsb_type::BrtBeginFills: - return fmt::format_to(ctx.out(), "BrtBeginFills"); - case xlsb_type::BrtEndFills: - return fmt::format_to(ctx.out(), "BrtEndFills"); - case xlsb_type::BrtBeginCellWatches: - return fmt::format_to(ctx.out(), "BrtBeginCellWatches"); - case xlsb_type::BrtEndCellWatches: - return fmt::format_to(ctx.out(), "BrtEndCellWatches"); - case xlsb_type::BrtCellWatch: - return fmt::format_to(ctx.out(), "BrtCellWatch"); - case xlsb_type::BrtBeginCRErrs: - return fmt::format_to(ctx.out(), "BrtBeginCRErrs"); - case xlsb_type::BrtEndCRErrs: - return fmt::format_to(ctx.out(), "BrtEndCRErrs"); - case xlsb_type::BrtCrashRecErr: - return fmt::format_to(ctx.out(), "BrtCrashRecErr"); - case xlsb_type::BrtBeginFonts: - return fmt::format_to(ctx.out(), "BrtBeginFonts"); - case xlsb_type::BrtEndFonts: - return fmt::format_to(ctx.out(), "BrtEndFonts"); - case xlsb_type::BrtBeginBorders: - return fmt::format_to(ctx.out(), "BrtBeginBorders"); - case xlsb_type::BrtEndBorders: - return fmt::format_to(ctx.out(), "BrtEndBorders"); - case xlsb_type::BrtBeginFmts: - return fmt::format_to(ctx.out(), "BrtBeginFmts"); - case xlsb_type::BrtEndFmts: - return fmt::format_to(ctx.out(), "BrtEndFmts"); - case xlsb_type::BrtBeginCellXFs: - return fmt::format_to(ctx.out(), "BrtBeginCellXFs"); - case xlsb_type::BrtEndCellXFs: - return fmt::format_to(ctx.out(), "BrtEndCellXFs"); - case xlsb_type::BrtBeginStyles: - return fmt::format_to(ctx.out(), "BrtBeginStyles"); - case xlsb_type::BrtEndStyles: - return fmt::format_to(ctx.out(), "BrtEndStyles"); - case xlsb_type::BrtBigName: - return fmt::format_to(ctx.out(), "BrtBigName"); - case xlsb_type::BrtBeginCellStyleXFs: - return fmt::format_to(ctx.out(), "BrtBeginCellStyleXFs"); - case xlsb_type::BrtEndCellStyleXFs: - return fmt::format_to(ctx.out(), "BrtEndCellStyleXFs"); - case xlsb_type::BrtBeginComments: - return fmt::format_to(ctx.out(), "BrtBeginComments"); - case xlsb_type::BrtEndComments: - return fmt::format_to(ctx.out(), "BrtEndComments"); - case xlsb_type::BrtBeginCommentAuthors: - return fmt::format_to(ctx.out(), "BrtBeginCommentAuthors"); - case xlsb_type::BrtEndCommentAuthors: - return fmt::format_to(ctx.out(), "BrtEndCommentAuthors"); - case xlsb_type::BrtCommentAuthor: - return fmt::format_to(ctx.out(), "BrtCommentAuthor"); - case xlsb_type::BrtBeginCommentList: - return fmt::format_to(ctx.out(), "BrtBeginCommentList"); - case xlsb_type::BrtEndCommentList: - return fmt::format_to(ctx.out(), "BrtEndCommentList"); - case xlsb_type::BrtBeginComment: - return fmt::format_to(ctx.out(), "BrtBeginComment"); - case xlsb_type::BrtEndComment: - return fmt::format_to(ctx.out(), "BrtEndComment"); - case xlsb_type::BrtCommentText: - return fmt::format_to(ctx.out(), "BrtCommentText"); - case xlsb_type::BrtBeginOleObjects: - return fmt::format_to(ctx.out(), "BrtBeginOleObjects"); - case xlsb_type::BrtOleObject: - return fmt::format_to(ctx.out(), "BrtOleObject"); - case xlsb_type::BrtEndOleObjects: - return fmt::format_to(ctx.out(), "BrtEndOleObjects"); - case xlsb_type::BrtBeginSxrules: - return fmt::format_to(ctx.out(), "BrtBeginSxrules"); - case xlsb_type::BrtEndSxRules: - return fmt::format_to(ctx.out(), "BrtEndSxRules"); - case xlsb_type::BrtBeginActiveXControls: - return fmt::format_to(ctx.out(), "BrtBeginActiveXControls"); - case xlsb_type::BrtActiveX: - return fmt::format_to(ctx.out(), "BrtActiveX"); - case xlsb_type::BrtEndActiveXControls: - return fmt::format_to(ctx.out(), "BrtEndActiveXControls"); - case xlsb_type::BrtBeginPCDSDTCEMembersSortBy: - return fmt::format_to(ctx.out(), "BrtBeginPCDSDTCEMembersSortBy"); - case xlsb_type::BrtBeginCellIgnoreECs: - return fmt::format_to(ctx.out(), "BrtBeginCellIgnoreECs"); - case xlsb_type::BrtCellIgnoreEC: - return fmt::format_to(ctx.out(), "BrtCellIgnoreEC"); - case xlsb_type::BrtEndCellIgnoreECs: - return fmt::format_to(ctx.out(), "BrtEndCellIgnoreECs"); - case xlsb_type::BrtCsProp: - return fmt::format_to(ctx.out(), "BrtCsProp"); - case xlsb_type::BrtCsPageSetup: - return fmt::format_to(ctx.out(), "BrtCsPageSetup"); - case xlsb_type::BrtBeginUserCsViews: - return fmt::format_to(ctx.out(), "BrtBeginUserCsViews"); - case xlsb_type::BrtEndUserCsViews: - return fmt::format_to(ctx.out(), "BrtEndUserCsViews"); - case xlsb_type::BrtBeginUserCsView: - return fmt::format_to(ctx.out(), "BrtBeginUserCsView"); - case xlsb_type::BrtEndUserCsView: - return fmt::format_to(ctx.out(), "BrtEndUserCsView"); - case xlsb_type::BrtBeginPcdSFCIEntries: - return fmt::format_to(ctx.out(), "BrtBeginPcdSFCIEntries"); - case xlsb_type::BrtEndPCDSFCIEntries: - return fmt::format_to(ctx.out(), "BrtEndPCDSFCIEntries"); - case xlsb_type::BrtPCDSFCIEntry: - return fmt::format_to(ctx.out(), "BrtPCDSFCIEntry"); - case xlsb_type::BrtBeginListParts: - return fmt::format_to(ctx.out(), "BrtBeginListParts"); - case xlsb_type::BrtListPart: - return fmt::format_to(ctx.out(), "BrtListPart"); - case xlsb_type::BrtEndListParts: - return fmt::format_to(ctx.out(), "BrtEndListParts"); - case xlsb_type::BrtSheetCalcProp: - return fmt::format_to(ctx.out(), "BrtSheetCalcProp"); - case xlsb_type::BrtBeginFnGroup: - return fmt::format_to(ctx.out(), "BrtBeginFnGroup"); - case xlsb_type::BrtFnGroup: - return fmt::format_to(ctx.out(), "BrtFnGroup"); - case xlsb_type::BrtEndFnGroup: - return fmt::format_to(ctx.out(), "BrtEndFnGroup"); - case xlsb_type::BrtSupAddin: - return fmt::format_to(ctx.out(), "BrtSupAddin"); - case xlsb_type::BrtSXTDMPOrder: - return fmt::format_to(ctx.out(), "BrtSXTDMPOrder"); - case xlsb_type::BrtCsProtection: - return fmt::format_to(ctx.out(), "BrtCsProtection"); - case xlsb_type::BrtBeginWsSortMap: - return fmt::format_to(ctx.out(), "BrtBeginWsSortMap"); - case xlsb_type::BrtEndWsSortMap: - return fmt::format_to(ctx.out(), "BrtEndWsSortMap"); - case xlsb_type::BrtBeginRRSort: - return fmt::format_to(ctx.out(), "BrtBeginRRSort"); - case xlsb_type::BrtEndRRSort: - return fmt::format_to(ctx.out(), "BrtEndRRSort"); - case xlsb_type::BrtRRSortItem: - return fmt::format_to(ctx.out(), "BrtRRSortItem"); - case xlsb_type::BrtFileSharingIso: - return fmt::format_to(ctx.out(), "BrtFileSharingIso"); - case xlsb_type::BrtBookProtectionIso: - return fmt::format_to(ctx.out(), "BrtBookProtectionIso"); - case xlsb_type::BrtSheetProtectionIso: - return fmt::format_to(ctx.out(), "BrtSheetProtectionIso"); - case xlsb_type::BrtCsProtectionIso: - return fmt::format_to(ctx.out(), "BrtCsProtectionIso"); - case xlsb_type::BrtRangeProtectionIso: - return fmt::format_to(ctx.out(), "BrtRangeProtectionIso"); - case xlsb_type::BrtDValList: - return fmt::format_to(ctx.out(), "BrtDValList"); - case xlsb_type::BrtRwDescent: - return fmt::format_to(ctx.out(), "BrtRwDescent"); - case xlsb_type::BrtKnownFonts: - return fmt::format_to(ctx.out(), "BrtKnownFonts"); - case xlsb_type::BrtBeginSXTupleSet: - return fmt::format_to(ctx.out(), "BrtBeginSXTupleSet"); - case xlsb_type::BrtEndSXTupleSet: - return fmt::format_to(ctx.out(), "BrtEndSXTupleSet"); - case xlsb_type::BrtBeginSXTupleSetHeader: - return fmt::format_to(ctx.out(), "BrtBeginSXTupleSetHeader"); - case xlsb_type::BrtEndSXTupleSetHeader: - return fmt::format_to(ctx.out(), "BrtEndSXTupleSetHeader"); - case xlsb_type::BrtSXTupleSetHeaderItem: - return fmt::format_to(ctx.out(), "BrtSXTupleSetHeaderItem"); - case xlsb_type::BrtBeginSXTupleSetData: - return fmt::format_to(ctx.out(), "BrtBeginSXTupleSetData"); - case xlsb_type::BrtEndSXTupleSetData: - return fmt::format_to(ctx.out(), "BrtEndSXTupleSetData"); - case xlsb_type::BrtBeginSXTupleSetRow: - return fmt::format_to(ctx.out(), "BrtBeginSXTupleSetRow"); - case xlsb_type::BrtEndSXTupleSetRow: - return fmt::format_to(ctx.out(), "BrtEndSXTupleSetRow"); - case xlsb_type::BrtSXTupleSetRowItem: - return fmt::format_to(ctx.out(), "BrtSXTupleSetRowItem"); - case xlsb_type::BrtNameExt: - return fmt::format_to(ctx.out(), "BrtNameExt"); - case xlsb_type::BrtPCDH14: - return fmt::format_to(ctx.out(), "BrtPCDH14"); - case xlsb_type::BrtBeginPCDCalcMem14: - return fmt::format_to(ctx.out(), "BrtBeginPCDCalcMem14"); - case xlsb_type::BrtEndPCDCalcMem14: - return fmt::format_to(ctx.out(), "BrtEndPCDCalcMem14"); - case xlsb_type::BrtSXTH14: - return fmt::format_to(ctx.out(), "BrtSXTH14"); - case xlsb_type::BrtBeginSparklineGroup: - return fmt::format_to(ctx.out(), "BrtBeginSparklineGroup"); - case xlsb_type::BrtEndSparklineGroup: - return fmt::format_to(ctx.out(), "BrtEndSparklineGroup"); - case xlsb_type::BrtSparkline: - return fmt::format_to(ctx.out(), "BrtSparkline"); - case xlsb_type::BrtSXDI14: - return fmt::format_to(ctx.out(), "BrtSXDI14"); - case xlsb_type::BrtWsFmtInfoEx14: - return fmt::format_to(ctx.out(), "BrtWsFmtInfoEx14"); - case xlsb_type::BrtBeginConditionalFormatting14: - return fmt::format_to(ctx.out(), "BrtBeginConditionalFormatting14"); - case xlsb_type::BrtEndConditionalFormatting14: - return fmt::format_to(ctx.out(), "BrtEndConditionalFormatting14"); - case xlsb_type::BrtBeginCFRule14: - return fmt::format_to(ctx.out(), "BrtBeginCFRule14"); - case xlsb_type::BrtEndCFRule14: - return fmt::format_to(ctx.out(), "BrtEndCFRule14"); - case xlsb_type::BrtCFVO14: - return fmt::format_to(ctx.out(), "BrtCFVO14"); - case xlsb_type::BrtBeginDatabar14: - return fmt::format_to(ctx.out(), "BrtBeginDatabar14"); - case xlsb_type::BrtBeginIconSet14: - return fmt::format_to(ctx.out(), "BrtBeginIconSet14"); - case xlsb_type::BrtDVal14: - return fmt::format_to(ctx.out(), "BrtDVal14"); - case xlsb_type::BrtBeginDVals14: - return fmt::format_to(ctx.out(), "BrtBeginDVals14"); - case xlsb_type::BrtColor14: - return fmt::format_to(ctx.out(), "BrtColor14"); - case xlsb_type::BrtBeginSparklines: - return fmt::format_to(ctx.out(), "BrtBeginSparklines"); - case xlsb_type::BrtEndSparklines: - return fmt::format_to(ctx.out(), "BrtEndSparklines"); - case xlsb_type::BrtBeginSparklineGroups: - return fmt::format_to(ctx.out(), "BrtBeginSparklineGroups"); - case xlsb_type::BrtEndSparklineGroups: - return fmt::format_to(ctx.out(), "BrtEndSparklineGroups"); - case xlsb_type::BrtSXVD14: - return fmt::format_to(ctx.out(), "BrtSXVD14"); - case xlsb_type::BrtBeginSxView14: - return fmt::format_to(ctx.out(), "BrtBeginSxView14"); - case xlsb_type::BrtEndSxView14: - return fmt::format_to(ctx.out(), "BrtEndSxView14"); - case xlsb_type::BrtBeginSXView16: - return fmt::format_to(ctx.out(), "BrtBeginSXView16"); - case xlsb_type::BrtEndSXView16: - return fmt::format_to(ctx.out(), "BrtEndSXView16"); - case xlsb_type::BrtBeginPCD14: - return fmt::format_to(ctx.out(), "BrtBeginPCD14"); - case xlsb_type::BrtEndPCD14: - return fmt::format_to(ctx.out(), "BrtEndPCD14"); - case xlsb_type::BrtBeginExtConn14: - return fmt::format_to(ctx.out(), "BrtBeginExtConn14"); - case xlsb_type::BrtEndExtConn14: - return fmt::format_to(ctx.out(), "BrtEndExtConn14"); - case xlsb_type::BrtBeginSlicerCacheIDs: - return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheIDs"); - case xlsb_type::BrtEndSlicerCacheIDs: - return fmt::format_to(ctx.out(), "BrtEndSlicerCacheIDs"); - case xlsb_type::BrtBeginSlicerCacheID: - return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheID"); - case xlsb_type::BrtEndSlicerCacheID: - return fmt::format_to(ctx.out(), "BrtEndSlicerCacheID"); - case xlsb_type::BrtBeginSlicerCache: - return fmt::format_to(ctx.out(), "BrtBeginSlicerCache"); - case xlsb_type::BrtEndSlicerCache: - return fmt::format_to(ctx.out(), "BrtEndSlicerCache"); - case xlsb_type::BrtBeginSlicerCacheDef: - return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheDef"); - case xlsb_type::BrtEndSlicerCacheDef: - return fmt::format_to(ctx.out(), "BrtEndSlicerCacheDef"); - case xlsb_type::BrtBeginSlicersEx: - return fmt::format_to(ctx.out(), "BrtBeginSlicersEx"); - case xlsb_type::BrtEndSlicersEx: - return fmt::format_to(ctx.out(), "BrtEndSlicersEx"); - case xlsb_type::BrtBeginSlicerEx: - return fmt::format_to(ctx.out(), "BrtBeginSlicerEx"); - case xlsb_type::BrtEndSlicerEx: - return fmt::format_to(ctx.out(), "BrtEndSlicerEx"); - case xlsb_type::BrtBeginSlicer: - return fmt::format_to(ctx.out(), "BrtBeginSlicer"); - case xlsb_type::BrtEndSlicer: - return fmt::format_to(ctx.out(), "BrtEndSlicer"); - case xlsb_type::BrtSlicerCachePivotTables: - return fmt::format_to(ctx.out(), "BrtSlicerCachePivotTables"); - case xlsb_type::BrtBeginSlicerCacheOlapImpl: - return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheOlapImpl"); - case xlsb_type::BrtEndSlicerCacheOlapImpl: - return fmt::format_to(ctx.out(), "BrtEndSlicerCacheOlapImpl"); - case xlsb_type::BrtBeginSlicerCacheLevelsData: - return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheLevelsData"); - case xlsb_type::BrtEndSlicerCacheLevelsData: - return fmt::format_to(ctx.out(), "BrtEndSlicerCacheLevelsData"); - case xlsb_type::BrtBeginSlicerCacheLevelData: - return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheLevelData"); - case xlsb_type::BrtEndSlicerCacheLevelData: - return fmt::format_to(ctx.out(), "BrtEndSlicerCacheLevelData"); - case xlsb_type::BrtBeginSlicerCacheSiRanges: - return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheSiRanges"); - case xlsb_type::BrtEndSlicerCacheSiRanges: - return fmt::format_to(ctx.out(), "BrtEndSlicerCacheSiRanges"); - case xlsb_type::BrtBeginSlicerCacheSiRange: - return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheSiRange"); - case xlsb_type::BrtEndSlicerCacheSiRange: - return fmt::format_to(ctx.out(), "BrtEndSlicerCacheSiRange"); - case xlsb_type::BrtSlicerCacheOlapItem: - return fmt::format_to(ctx.out(), "BrtSlicerCacheOlapItem"); - case xlsb_type::BrtBeginSlicerCacheSelections: - return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheSelections"); - case xlsb_type::BrtSlicerCacheSelection: - return fmt::format_to(ctx.out(), "BrtSlicerCacheSelection"); - case xlsb_type::BrtEndSlicerCacheSelections: - return fmt::format_to(ctx.out(), "BrtEndSlicerCacheSelections"); - case xlsb_type::BrtBeginSlicerCacheNative: - return fmt::format_to(ctx.out(), "BrtBeginSlicerCacheNative"); - case xlsb_type::BrtEndSlicerCacheNative: - return fmt::format_to(ctx.out(), "BrtEndSlicerCacheNative"); - case xlsb_type::BrtSlicerCacheNativeItem: - return fmt::format_to(ctx.out(), "BrtSlicerCacheNativeItem"); - case xlsb_type::BrtRangeProtection14: - return fmt::format_to(ctx.out(), "BrtRangeProtection14"); - case xlsb_type::BrtRangeProtectionIso14: - return fmt::format_to(ctx.out(), "BrtRangeProtectionIso14"); - case xlsb_type::BrtCellIgnoreEC14: - return fmt::format_to(ctx.out(), "BrtCellIgnoreEC14"); - case xlsb_type::BrtList14: - return fmt::format_to(ctx.out(), "BrtList14"); - case xlsb_type::BrtCFIcon: - return fmt::format_to(ctx.out(), "BrtCFIcon"); - case xlsb_type::BrtBeginSlicerCachesPivotCacheIDs: - return fmt::format_to(ctx.out(), "BrtBeginSlicerCachesPivotCacheIDs"); - case xlsb_type::BrtEndSlicerCachesPivotCacheIDs: - return fmt::format_to(ctx.out(), "BrtEndSlicerCachesPivotCacheIDs"); - case xlsb_type::BrtBeginSlicers: - return fmt::format_to(ctx.out(), "BrtBeginSlicers"); - case xlsb_type::BrtEndSlicers: - return fmt::format_to(ctx.out(), "BrtEndSlicers"); - case xlsb_type::BrtWbProp14: - return fmt::format_to(ctx.out(), "BrtWbProp14"); - case xlsb_type::BrtBeginSXEdit: - return fmt::format_to(ctx.out(), "BrtBeginSXEdit"); - case xlsb_type::BrtEndSXEdit: - return fmt::format_to(ctx.out(), "BrtEndSXEdit"); - case xlsb_type::BrtBeginSXEdits: - return fmt::format_to(ctx.out(), "BrtBeginSXEdits"); - case xlsb_type::BrtEndSXEdits: - return fmt::format_to(ctx.out(), "BrtEndSXEdits"); - case xlsb_type::BrtBeginSXChange: - return fmt::format_to(ctx.out(), "BrtBeginSXChange"); - case xlsb_type::BrtEndSXChange: - return fmt::format_to(ctx.out(), "BrtEndSXChange"); - case xlsb_type::BrtBeginSXChanges: - return fmt::format_to(ctx.out(), "BrtBeginSXChanges"); - case xlsb_type::BrtEndSXChanges: - return fmt::format_to(ctx.out(), "BrtEndSXChanges"); - case xlsb_type::BrtSXTupleItems: - return fmt::format_to(ctx.out(), "BrtSXTupleItems"); - case xlsb_type::BrtBeginSlicerStyle: - return fmt::format_to(ctx.out(), "BrtBeginSlicerStyle"); - case xlsb_type::BrtEndSlicerStyle: - return fmt::format_to(ctx.out(), "BrtEndSlicerStyle"); - case xlsb_type::BrtSlicerStyleElement: - return fmt::format_to(ctx.out(), "BrtSlicerStyleElement"); - case xlsb_type::BrtBeginStyleSheetExt14: - return fmt::format_to(ctx.out(), "BrtBeginStyleSheetExt14"); - case xlsb_type::BrtEndStyleSheetExt14: - return fmt::format_to(ctx.out(), "BrtEndStyleSheetExt14"); - case xlsb_type::BrtBeginSlicerCachesPivotCacheID: - return fmt::format_to(ctx.out(), "BrtBeginSlicerCachesPivotCacheID"); - case xlsb_type::BrtEndSlicerCachesPivotCacheID: - return fmt::format_to(ctx.out(), "BrtEndSlicerCachesPivotCacheID"); - case xlsb_type::BrtBeginConditionalFormattings: - return fmt::format_to(ctx.out(), "BrtBeginConditionalFormattings"); - case xlsb_type::BrtEndConditionalFormattings: - return fmt::format_to(ctx.out(), "BrtEndConditionalFormattings"); - case xlsb_type::BrtBeginPCDCalcMemExt: - return fmt::format_to(ctx.out(), "BrtBeginPCDCalcMemExt"); - case xlsb_type::BrtEndPCDCalcMemExt: - return fmt::format_to(ctx.out(), "BrtEndPCDCalcMemExt"); - case xlsb_type::BrtBeginPCDCalcMemsExt: - return fmt::format_to(ctx.out(), "BrtBeginPCDCalcMemsExt"); - case xlsb_type::BrtEndPCDCalcMemsExt: - return fmt::format_to(ctx.out(), "BrtEndPCDCalcMemsExt"); - case xlsb_type::BrtPCDField14: - return fmt::format_to(ctx.out(), "BrtPCDField14"); - case xlsb_type::BrtBeginSlicerStyles: - return fmt::format_to(ctx.out(), "BrtBeginSlicerStyles"); - case xlsb_type::BrtEndSlicerStyles: - return fmt::format_to(ctx.out(), "BrtEndSlicerStyles"); - case xlsb_type::BrtBeginSlicerStyleElements: - return fmt::format_to(ctx.out(), "BrtBeginSlicerStyleElements"); - case xlsb_type::BrtEndSlicerStyleElements: - return fmt::format_to(ctx.out(), "BrtEndSlicerStyleElements"); - case xlsb_type::BrtCFRuleExt: - return fmt::format_to(ctx.out(), "BrtCFRuleExt"); - case xlsb_type::BrtBeginSXCondFmt14: - return fmt::format_to(ctx.out(), "BrtBeginSXCondFmt14"); - case xlsb_type::BrtEndSXCondFmt14: - return fmt::format_to(ctx.out(), "BrtEndSXCondFmt14"); - case xlsb_type::BrtBeginSXCondFmts14: - return fmt::format_to(ctx.out(), "BrtBeginSXCondFmts14"); - case xlsb_type::BrtEndSXCondFmts14: - return fmt::format_to(ctx.out(), "BrtEndSXCondFmts14"); - case xlsb_type::BrtBeginSortCond14: - return fmt::format_to(ctx.out(), "BrtBeginSortCond14"); - case xlsb_type::BrtEndSortCond14: - return fmt::format_to(ctx.out(), "BrtEndSortCond14"); - case xlsb_type::BrtEndDVals14: - return fmt::format_to(ctx.out(), "BrtEndDVals14"); - case xlsb_type::BrtEndIconSet14: - return fmt::format_to(ctx.out(), "BrtEndIconSet14"); - case xlsb_type::BrtEndDatabar14: - return fmt::format_to(ctx.out(), "BrtEndDatabar14"); - case xlsb_type::BrtBeginColorScale14: - return fmt::format_to(ctx.out(), "BrtBeginColorScale14"); - case xlsb_type::BrtEndColorScale14: - return fmt::format_to(ctx.out(), "BrtEndColorScale14"); - case xlsb_type::BrtBeginSxrules14: - return fmt::format_to(ctx.out(), "BrtBeginSxrules14"); - case xlsb_type::BrtEndSxrules14: - return fmt::format_to(ctx.out(), "BrtEndSxrules14"); - case xlsb_type::BrtBeginPRule14: - return fmt::format_to(ctx.out(), "BrtBeginPRule14"); - case xlsb_type::BrtEndPRule14: - return fmt::format_to(ctx.out(), "BrtEndPRule14"); - case xlsb_type::BrtBeginPRFilters14: - return fmt::format_to(ctx.out(), "BrtBeginPRFilters14"); - case xlsb_type::BrtEndPRFilters14: - return fmt::format_to(ctx.out(), "BrtEndPRFilters14"); - case xlsb_type::BrtBeginPRFilter14: - return fmt::format_to(ctx.out(), "BrtBeginPRFilter14"); - case xlsb_type::BrtEndPRFilter14: - return fmt::format_to(ctx.out(), "BrtEndPRFilter14"); - case xlsb_type::BrtBeginPRFItem14: - return fmt::format_to(ctx.out(), "BrtBeginPRFItem14"); - case xlsb_type::BrtEndPRFItem14: - return fmt::format_to(ctx.out(), "BrtEndPRFItem14"); - case xlsb_type::BrtBeginCellIgnoreECs14: - return fmt::format_to(ctx.out(), "BrtBeginCellIgnoreECs14"); - case xlsb_type::BrtEndCellIgnoreECs14: - return fmt::format_to(ctx.out(), "BrtEndCellIgnoreECs14"); - case xlsb_type::BrtDxf14: - return fmt::format_to(ctx.out(), "BrtDxf14"); - case xlsb_type::BrtBeginDxF14s: - return fmt::format_to(ctx.out(), "BrtBeginDxF14s"); - case xlsb_type::BrtEndDxf14s: - return fmt::format_to(ctx.out(), "BrtEndDxf14s"); - case xlsb_type::BrtFilter14: - return fmt::format_to(ctx.out(), "BrtFilter14"); - case xlsb_type::BrtBeginCustomFilters14: - return fmt::format_to(ctx.out(), "BrtBeginCustomFilters14"); - case xlsb_type::BrtCustomFilter14: - return fmt::format_to(ctx.out(), "BrtCustomFilter14"); - case xlsb_type::BrtIconFilter14: - return fmt::format_to(ctx.out(), "BrtIconFilter14"); - case xlsb_type::BrtPivotCacheConnectionName: - return fmt::format_to(ctx.out(), "BrtPivotCacheConnectionName"); - case xlsb_type::BrtBeginDecoupledPivotCacheIDs: - return fmt::format_to(ctx.out(), "BrtBeginDecoupledPivotCacheIDs"); - case xlsb_type::BrtEndDecoupledPivotCacheIDs: - return fmt::format_to(ctx.out(), "BrtEndDecoupledPivotCacheIDs"); - case xlsb_type::BrtDecoupledPivotCacheID: - return fmt::format_to(ctx.out(), "BrtDecoupledPivotCacheID"); - case xlsb_type::BrtBeginPivotTableRefs: - return fmt::format_to(ctx.out(), "BrtBeginPivotTableRefs"); - case xlsb_type::BrtEndPivotTableRefs: - return fmt::format_to(ctx.out(), "BrtEndPivotTableRefs"); - case xlsb_type::BrtPivotTableRef: - return fmt::format_to(ctx.out(), "BrtPivotTableRef"); - case xlsb_type::BrtSlicerCacheBookPivotTables: - return fmt::format_to(ctx.out(), "BrtSlicerCacheBookPivotTables"); - case xlsb_type::BrtBeginSxvcells: - return fmt::format_to(ctx.out(), "BrtBeginSxvcells"); - case xlsb_type::BrtEndSxvcells: - return fmt::format_to(ctx.out(), "BrtEndSxvcells"); - case xlsb_type::BrtBeginSxRow: - return fmt::format_to(ctx.out(), "BrtBeginSxRow"); - case xlsb_type::BrtEndSxRow: - return fmt::format_to(ctx.out(), "BrtEndSxRow"); - case xlsb_type::BrtPcdCalcMem15: - return fmt::format_to(ctx.out(), "BrtPcdCalcMem15"); - case xlsb_type::BrtQsi15: - return fmt::format_to(ctx.out(), "BrtQsi15"); - case xlsb_type::BrtBeginWebExtensions: - return fmt::format_to(ctx.out(), "BrtBeginWebExtensions"); - case xlsb_type::BrtEndWebExtensions: - return fmt::format_to(ctx.out(), "BrtEndWebExtensions"); - case xlsb_type::BrtWebExtension: - return fmt::format_to(ctx.out(), "BrtWebExtension"); - case xlsb_type::BrtAbsPath15: - return fmt::format_to(ctx.out(), "BrtAbsPath15"); - case xlsb_type::BrtBeginPivotTableUISettings: - return fmt::format_to(ctx.out(), "BrtBeginPivotTableUISettings"); - case xlsb_type::BrtEndPivotTableUISettings: - return fmt::format_to(ctx.out(), "BrtEndPivotTableUISettings"); - case xlsb_type::BrtTableSlicerCacheIDs: - return fmt::format_to(ctx.out(), "BrtTableSlicerCacheIDs"); - case xlsb_type::BrtTableSlicerCacheID: - return fmt::format_to(ctx.out(), "BrtTableSlicerCacheID"); - case xlsb_type::BrtBeginTableSlicerCache: - return fmt::format_to(ctx.out(), "BrtBeginTableSlicerCache"); - case xlsb_type::BrtEndTableSlicerCache: - return fmt::format_to(ctx.out(), "BrtEndTableSlicerCache"); - case xlsb_type::BrtSxFilter15: - return fmt::format_to(ctx.out(), "BrtSxFilter15"); - case xlsb_type::BrtBeginTimelineCachePivotCacheIDs: - return fmt::format_to(ctx.out(), "BrtBeginTimelineCachePivotCacheIDs"); - case xlsb_type::BrtEndTimelineCachePivotCacheIDs: - return fmt::format_to(ctx.out(), "BrtEndTimelineCachePivotCacheIDs"); - case xlsb_type::BrtTimelineCachePivotCacheID: - return fmt::format_to(ctx.out(), "BrtTimelineCachePivotCacheID"); - case xlsb_type::BrtBeginTimelineCacheIDs: - return fmt::format_to(ctx.out(), "BrtBeginTimelineCacheIDs"); - case xlsb_type::BrtEndTimelineCacheIDs: - return fmt::format_to(ctx.out(), "BrtEndTimelineCacheIDs"); - case xlsb_type::BrtBeginTimelineCacheID: - return fmt::format_to(ctx.out(), "BrtBeginTimelineCacheID"); - case xlsb_type::BrtEndTimelineCacheID: - return fmt::format_to(ctx.out(), "BrtEndTimelineCacheID"); - case xlsb_type::BrtBeginTimelinesEx: - return fmt::format_to(ctx.out(), "BrtBeginTimelinesEx"); - case xlsb_type::BrtEndTimelinesEx: - return fmt::format_to(ctx.out(), "BrtEndTimelinesEx"); - case xlsb_type::BrtBeginTimelineEx: - return fmt::format_to(ctx.out(), "BrtBeginTimelineEx"); - case xlsb_type::BrtEndTimelineEx: - return fmt::format_to(ctx.out(), "BrtEndTimelineEx"); - case xlsb_type::BrtWorkBookPr15: - return fmt::format_to(ctx.out(), "BrtWorkBookPr15"); - case xlsb_type::BrtPCDH15: - return fmt::format_to(ctx.out(), "BrtPCDH15"); - case xlsb_type::BrtBeginTimelineStyle: - return fmt::format_to(ctx.out(), "BrtBeginTimelineStyle"); - case xlsb_type::BrtEndTimelineStyle: - return fmt::format_to(ctx.out(), "BrtEndTimelineStyle"); - case xlsb_type::BrtTimelineStyleElement: - return fmt::format_to(ctx.out(), "BrtTimelineStyleElement"); - case xlsb_type::BrtBeginTimelineStylesheetExt15: - return fmt::format_to(ctx.out(), "BrtBeginTimelineStylesheetExt15"); - case xlsb_type::BrtEndTimelineStylesheetExt15: - return fmt::format_to(ctx.out(), "BrtEndTimelineStylesheetExt15"); - case xlsb_type::BrtBeginTimelineStyles: - return fmt::format_to(ctx.out(), "BrtBeginTimelineStyles"); - case xlsb_type::BrtEndTimelineStyles: - return fmt::format_to(ctx.out(), "BrtEndTimelineStyles"); - case xlsb_type::BrtBeginTimelineStyleElements: - return fmt::format_to(ctx.out(), "BrtBeginTimelineStyleElements"); - case xlsb_type::BrtEndTimelineStyleElements: - return fmt::format_to(ctx.out(), "BrtEndTimelineStyleElements"); - case xlsb_type::BrtDxf15: - return fmt::format_to(ctx.out(), "BrtDxf15"); - case xlsb_type::BrtBeginDxfs15: - return fmt::format_to(ctx.out(), "BrtBeginDxfs15"); - case xlsb_type::BrtEndDXFs15: - return fmt::format_to(ctx.out(), "BrtEndDXFs15"); - case xlsb_type::BrtSlicerCacheHideItemsWithNoData: - return fmt::format_to(ctx.out(), "BrtSlicerCacheHideItemsWithNoData"); - case xlsb_type::BrtBeginItemUniqueNames: - return fmt::format_to(ctx.out(), "BrtBeginItemUniqueNames"); - case xlsb_type::BrtEndItemUniqueNames: - return fmt::format_to(ctx.out(), "BrtEndItemUniqueNames"); - case xlsb_type::BrtItemUniqueName: - return fmt::format_to(ctx.out(), "BrtItemUniqueName"); - case xlsb_type::BrtBeginExtConn15: - return fmt::format_to(ctx.out(), "BrtBeginExtConn15"); - case xlsb_type::BrtEndExtConn15: - return fmt::format_to(ctx.out(), "BrtEndExtConn15"); - case xlsb_type::BrtBeginOledbPr15: - return fmt::format_to(ctx.out(), "BrtBeginOledbPr15"); - case xlsb_type::BrtEndOledbPr15: - return fmt::format_to(ctx.out(), "BrtEndOledbPr15"); - case xlsb_type::BrtBeginDataFeedPr15: - return fmt::format_to(ctx.out(), "BrtBeginDataFeedPr15"); - case xlsb_type::BrtEndDataFeedPr15: - return fmt::format_to(ctx.out(), "BrtEndDataFeedPr15"); - case xlsb_type::BrtTextPr15: - return fmt::format_to(ctx.out(), "BrtTextPr15"); - case xlsb_type::BrtRangePr15: - return fmt::format_to(ctx.out(), "BrtRangePr15"); - case xlsb_type::BrtDbCommand15: - return fmt::format_to(ctx.out(), "BrtDbCommand15"); - case xlsb_type::BrtBeginDbTables15: - return fmt::format_to(ctx.out(), "BrtBeginDbTables15"); - case xlsb_type::BrtEndDbTables15: - return fmt::format_to(ctx.out(), "BrtEndDbTables15"); - case xlsb_type::BrtDbTable15: - return fmt::format_to(ctx.out(), "BrtDbTable15"); - case xlsb_type::BrtBeginDataModel: - return fmt::format_to(ctx.out(), "BrtBeginDataModel"); - case xlsb_type::BrtEndDataModel: - return fmt::format_to(ctx.out(), "BrtEndDataModel"); - case xlsb_type::BrtBeginModelTables: - return fmt::format_to(ctx.out(), "BrtBeginModelTables"); - case xlsb_type::BrtEndModelTables: - return fmt::format_to(ctx.out(), "BrtEndModelTables"); - case xlsb_type::BrtModelTable: - return fmt::format_to(ctx.out(), "BrtModelTable"); - case xlsb_type::BrtBeginModelRelationships: - return fmt::format_to(ctx.out(), "BrtBeginModelRelationships"); - case xlsb_type::BrtEndModelRelationships: - return fmt::format_to(ctx.out(), "BrtEndModelRelationships"); - case xlsb_type::BrtModelRelationship: - return fmt::format_to(ctx.out(), "BrtModelRelationship"); - case xlsb_type::BrtBeginECTxtWiz15: - return fmt::format_to(ctx.out(), "BrtBeginECTxtWiz15"); - case xlsb_type::BrtEndECTxtWiz15: - return fmt::format_to(ctx.out(), "BrtEndECTxtWiz15"); - case xlsb_type::BrtBeginECTWFldInfoLst15: - return fmt::format_to(ctx.out(), "BrtBeginECTWFldInfoLst15"); - case xlsb_type::BrtEndECTWFldInfoLst15: - return fmt::format_to(ctx.out(), "BrtEndECTWFldInfoLst15"); - case xlsb_type::BrtBeginECTWFldInfo15: - return fmt::format_to(ctx.out(), "BrtBeginECTWFldInfo15"); - case xlsb_type::BrtFieldListActiveItem: - return fmt::format_to(ctx.out(), "BrtFieldListActiveItem"); - case xlsb_type::BrtPivotCacheIdVersion: - return fmt::format_to(ctx.out(), "BrtPivotCacheIdVersion"); - case xlsb_type::BrtSXDI15: - return fmt::format_to(ctx.out(), "BrtSXDI15"); - case xlsb_type::brtBeginModelTimeGroupings: - return fmt::format_to(ctx.out(), "brtBeginModelTimeGroupings"); - case xlsb_type::brtEndModelTimeGroupings: - return fmt::format_to(ctx.out(), "brtEndModelTimeGroupings"); - case xlsb_type::brtBeginModelTimeGrouping: - return fmt::format_to(ctx.out(), "brtBeginModelTimeGrouping"); - case xlsb_type::brtEndModelTimeGrouping: - return fmt::format_to(ctx.out(), "brtEndModelTimeGrouping"); - case xlsb_type::brtModelTimeGroupingCalcCol: - return fmt::format_to(ctx.out(), "brtModelTimeGroupingCalcCol"); - case xlsb_type::brtRevisionPtr: - return fmt::format_to(ctx.out(), "brtRevisionPtr"); - case xlsb_type::BrtBeginDynamicArrayPr: - return fmt::format_to(ctx.out(), "BrtBeginDynamicArrayPr"); - case xlsb_type::BrtEndDynamicArrayPr: - return fmt::format_to(ctx.out(), "BrtEndDynamicArrayPr"); - case xlsb_type::BrtBeginRichValueBlock: - return fmt::format_to(ctx.out(), "BrtBeginRichValueBlock"); - case xlsb_type::BrtEndRichValueBlock: - return fmt::format_to(ctx.out(), "BrtEndRichValueBlock"); - case xlsb_type::BrtBeginRichFilters: - return fmt::format_to(ctx.out(), "BrtBeginRichFilters"); - case xlsb_type::BrtEndRichFilters: - return fmt::format_to(ctx.out(), "BrtEndRichFilters"); - case xlsb_type::BrtRichFilter: - return fmt::format_to(ctx.out(), "BrtRichFilter"); - case xlsb_type::BrtBeginRichFilterColumn: - return fmt::format_to(ctx.out(), "BrtBeginRichFilterColumn"); - case xlsb_type::BrtEndRichFilterColumn: - return fmt::format_to(ctx.out(), "BrtEndRichFilterColumn"); - case xlsb_type::BrtBeginCustomRichFilters: - return fmt::format_to(ctx.out(), "BrtBeginCustomRichFilters"); - case xlsb_type::BrtEndCustomRichFilters: - return fmt::format_to(ctx.out(), "BrtEndCustomRichFilters"); - case xlsb_type::BRTCustomRichFilter: - return fmt::format_to(ctx.out(), "BRTCustomRichFilter"); - case xlsb_type::BrtTop10RichFilter: - return fmt::format_to(ctx.out(), "BrtTop10RichFilter"); - case xlsb_type::BrtDynamicRichFilter: - return fmt::format_to(ctx.out(), "BrtDynamicRichFilter"); - case xlsb_type::BrtBeginRichSortCondition: - return fmt::format_to(ctx.out(), "BrtBeginRichSortCondition"); - case xlsb_type::BrtEndRichSortCondition: - return fmt::format_to(ctx.out(), "BrtEndRichSortCondition"); - case xlsb_type::BrtRichFilterDateGroupItem: - return fmt::format_to(ctx.out(), "BrtRichFilterDateGroupItem"); - case xlsb_type::BrtBeginCalcFeatures: - return fmt::format_to(ctx.out(), "BrtBeginCalcFeatures"); - case xlsb_type::BrtEndCalcFeatures: - return fmt::format_to(ctx.out(), "BrtEndCalcFeatures"); - case xlsb_type::BrtCalcFeature: - return fmt::format_to(ctx.out(), "BrtCalcFeature"); - case xlsb_type::BrtExternalLinksPr: - return fmt::format_to(ctx.out(), "BrtExternalLinksPr"); - default: - return fmt::format_to(ctx.out(), "{}", (unsigned int)t); - } - } -}; - -struct brt_bundle_sh { - uint32_t hsState; - uint32_t iTabID; -}; - -#pragma pack(push,1) - -struct brt_row_hdr { - uint32_t rw; - uint32_t ixfe; - uint16_t miyRw; - // FIXME - make sure bitfields are in correct order - uint16_t fExtraAsc : 1; - uint16_t fExtraDsc : 1; - uint16_t reserved1 : 6; - uint16_t iOutLevel : 3; - uint16_t fCollapsed : 1; - uint16_t fDyZero : 1; - uint16_t fUnsynced : 1; - uint16_t fGhostDirty : 1; - uint16_t fReserved : 1; - uint8_t fPhShow : 1; - uint8_t reserved2 : 7; - uint32_t ccolspan; -}; - -struct xlsb_cell { - uint32_t column; - uint32_t iStyleRef : 24; - uint32_t fPhShow : 1; - uint32_t reserved : 7; -}; - -struct rk_number { - uint32_t fx100 : 1; - uint32_t fInt : 1; - uint32_t num : 30; -}; - -#pragma pack(pop) - -struct brt_cell_rk { - xlsb_cell cell; - rk_number value; -}; - -struct brt_cell_bool { - xlsb_cell cell; - uint8_t fBool; -}; - -struct brt_cell_real { - xlsb_cell cell; - double xnum; -}; - -struct brt_cell_st { - xlsb_cell cell; - uint32_t len; - char16_t str[0]; -}; - -#pragma pack(push,1) - -struct rich_str { - uint8_t fRichStr : 1; - uint8_t fExtStr : 1; - uint8_t unused1 : 6; - uint32_t len; - char16_t str[0]; -}; - -#pragma pack(pop) - -struct brt_sst_item { - rich_str richStr; -}; - -struct brt_cell_rstring { - xlsb_cell cell; - rich_str value; -}; - -struct brt_cell_isst { - xlsb_cell cell; - uint32_t isst; -}; - -#pragma pack(push,1) - -struct brt_xf { - uint16_t ixfeParent; - uint16_t iFmt; - uint16_t iFont; - uint16_t iFill; - uint16_t ixBOrder; - uint8_t trot; - uint8_t indent; - uint16_t f123Prefix : 1; - uint16_t fSxButton : 1; - uint16_t fHidden : 1; - uint16_t fLocked : 1; - uint16_t iReadingOrder : 2; - uint16_t fMergeCell : 1; - uint16_t fShrinkToFit : 1; - uint16_t fJustLast : 1; - uint16_t fWrap : 1; - uint16_t alcv : 3; - uint16_t alc : 3; - uint16_t unused : 10; - uint16_t xfGrbitAtr : 6; -}; - -#pragma pack(pop) - -struct brt_wb_prop { - uint32_t f1904 : 1; - uint32_t reserved1 : 1; - uint32_t fHideBorderUnselLists : 1; - uint32_t fFilterPrivacy : 1; - uint32_t fBuggedUserABoutSolution : 1; - uint32_t fShowInkAnnotation : 1; - uint32_t fBackup : 1; - uint32_t fNoSaveSup : 1; - uint32_t grbitUpdateLinks : 2; - uint32_t fHidePivotTableFList : 1; - uint32_t fPublishedBookItems : 1; - uint32_t fCheckCompat : 1; - uint32_t mdDspObj : 2; - uint32_t fShowPivotChartFilter : 1; - uint32_t fAutoCompressPictures : 1; - uint32_t reserved2 : 1; - uint32_t fRefreshAll : 1; - uint32_t unused : 13; - uint32_t dwThemeVersion; - uint32_t strName_len; -}; - -#pragma pack(push,1) - -struct brt_fmt { - uint16_t ifmt; - uint32_t stFmtCode_len; - char16_t stFmtCode[0]; -}; - -#pragma pack(pop) diff --git a/src/xlcpp/xml-reader.cpp b/src/xlcpp/xml-reader.cpp index baaca6d79..4bf09c521 100644 --- a/src/xlcpp/xml-reader.cpp +++ b/src/xlcpp/xml-reader.cpp @@ -336,63 +336,3 @@ static string esc_char(string_view s) { return string{string_view(t, 4)}; } } - -string xml_enc_string_view::decode() const { - auto v = sv; - string s; - - s.reserve(v.length()); - - while (!v.empty()) { - if (v.front() == '&') { - v.remove_prefix(1); - - if (v.starts_with("amp;")) { - s += "&"; - v.remove_prefix(4); - } else if (v.starts_with("lt;")) { - s += "<"; - v.remove_prefix(3); - } else if (v.starts_with("gt;")) { - s += ">"; - v.remove_prefix(3); - } else if (v.starts_with("quot;")) { - s += "\""; - v.remove_prefix(5); - } else if (v.starts_with("apos;")) { - s += "'"; - v.remove_prefix(5); - } else if (v.starts_with("#")) { - string_view bit; - - v.remove_prefix(1); - - auto sc = v.find_first_of(';'); - if (sc == string::npos) { - bit = v; - v = ""; - } else { - bit = v.substr(0, sc); - v.remove_prefix(sc + 1); - } - - s += esc_char(bit); - } else - s += "&"; - } else { - s += v.front(); - v.remove_prefix(1); - } - } - - return s; -} - -bool xml_enc_string_view::cmp(string_view str) const { - for (auto c : sv) { - if (c == '&') - return decode() == str; - } - - return sv == str; -} diff --git a/src/xlcpp/xml-writer.cpp b/src/xlcpp/xml-writer.cpp deleted file mode 100644 index 421d0d992..000000000 --- a/src/xlcpp/xml-writer.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "xlcpp-pimpl.h" - -using namespace std; - -string xml_writer::dump() const { - return buf; -} - -void xml_writer::start_document() { - buf += "\n"; - empty_tag = false; -} - -static string xml_escape(string_view s, bool att) { - string ret; - - ret.reserve(s.length()); - - for (auto c : s) { - if (c == '<') - ret += "<"; - else if (c == '>') - ret += ">"; - else if (c == '&') - ret += "&"; - else if (c == '"' && att) - ret += """; - else - ret += c; - } - - return ret; -} - -void xml_writer::start_element(string_view tag, const unordered_map& namespaces) { - if (empty_tag) - buf += ">"; - - buf += "<" + string{tag}; - tags.emplace(tag); - - empty_tag = true; - - for (const auto& ns : namespaces) { - buf += " xmlns"; - - if (!ns.first.empty()) - buf += ":" + ns.first; - - buf += "=\""; - buf += xml_escape(ns.second, true); - buf += "\""; - } -} - -void xml_writer::end_element() { - if (empty_tag) { - buf += "/>"; - empty_tag = false; - } else - buf += ""; - - tags.pop(); -} - -void xml_writer::text(string_view s) { - if (empty_tag) { - buf += ">"; - empty_tag = false; - } - - buf += xml_escape(s, false); -} - -void xml_writer::attribute(string_view name, string_view value) { - buf += " " + string{name} + "=\"" + xml_escape(value, true) + "\""; -} From 4959ec24af106dd7e3bde08ccf21d22e4cdce582 Mon Sep 17 00:00:00 2001 From: Jan Marvin Garbuszus Date: Sun, 16 Jul 2023 23:25:20 +0200 Subject: [PATCH 4/9] Remove much of what we don't need --- configure | 78 ------------------------------------ src/Makevars | 35 ++++++++-------- src/Makevars.in | 39 ------------------ src/xlcpp/xlcpp-pimpl.h | 86 ++++++++++++++++++++-------------------- src/xlcpp/xlcpp.cpp | 22 +++++----- src/xlcpp/xml-reader.cpp | 60 ++++++++++++++++++++++++++++ 6 files changed, 130 insertions(+), 190 deletions(-) delete mode 100755 configure delete mode 100644 src/Makevars.in diff --git a/configure b/configure deleted file mode 100755 index e984c6134..000000000 --- a/configure +++ /dev/null @@ -1,78 +0,0 @@ -# Anticonf (tm) script by Jeroen Ooms, Jim Hester (2017) -# This script will query 'pkg-config' for the required cflags and ldflags. -# If pkg-config is unavailable or does not find the library, try setting -# INCLUDE_DIR and LIB_DIR manually via e.g: -# R CMD INSTALL --configure-vars='INCLUDE_DIR=/.../include LIB_DIR=/.../lib' - -# Library settings -PKG_CONFIG_NAME="libarchive" -PKG_DEB_NAME="libarchive-dev" -PKG_RPM_NAME="libarchive-devel" -PKG_CSW_NAME="libarchive_dev" -PKG_BREW_NAME="libarchive" -PKG_TEST_HEADER="" -PKG_LIBS=-larchive - -# Use pkg-config if available -pkg-config ${PKG_CONFIG_NAME} --atleast-version=1.0 2>/dev/null -if [ $? -eq 0 ]; then - PKGCONFIG_CFLAGS=`pkg-config --cflags ${PKG_CONFIG_NAME}` - PKGCONFIG_LIBS=`pkg-config --libs ${PKG_CONFIG_NAME}` -fi - -# Note that cflags may be empty in case of success -if [ "$INCLUDE_DIR" ] || [ "$LIB_DIR" ]; then - echo "Found INCLUDE_DIR and/or LIB_DIR!" - PKG_CFLAGS="-I$INCLUDE_DIR $PKG_CFLAGS" - PKG_LIBS="-L$LIB_DIR $PKG_LIBS" -elif [ "$PKGCONFIG_CFLAGS" ] || [ "$PKGCONFIG_LIBS" ]; then - echo "Found pkg-config cflags and libs!" - PKG_CFLAGS=${PKGCONFIG_CFLAGS} - PKG_LIBS=${PKGCONFIG_LIBS} -elif [ `uname` = "Darwin" ]; then - test ! "$CI" && brew --version 2>/dev/null - if [ $? -eq 0 ]; then - BREWDIR=`brew --prefix` - PKG_CFLAGS="-I$BREWDIR/opt/libarchive/include" - PKG_LIBS="-L$BREWDIR/opt/libarchive/lib $PKG_LIBS" - else - curl -sfL "https://autobrew.github.io/scripts/$PKG_BREW_NAME" > autobrew - . ./autobrew - fi -fi - -# Find compiler -CXX20=`${R_HOME}/bin/R CMD config CXX20` -CXX20FLAGS=`${R_HOME}/bin/R CMD config CXX20FLAGS` -CPPFLAGS=`${R_HOME}/bin/R CMD config CPPFLAGS` - -# For debugging -echo "PKG_CFLAGS=$PKG_CFLAGS" -echo "PKG_LIBS=$PKG_LIBS" - -# Test configuration -echo "#include $PKG_TEST_HEADER" | ${CXX20} ${CPPFLAGS} ${PKG_CFLAGS} ${CXX20FLAGS} -E -xc++ - > /dev/null - -# Customize the error -if [ $? -ne 0 ]; then - echo "--------------------------- [ANTICONF] --------------------------------" - echo "Configuration failed because $PKG_CONFIG_NAME was not found. Try installing:" - echo " * deb: $PKG_DEB_NAME (Debian, Ubuntu, etc)" - echo " * rpm: $PKG_RPM_NAME (Fedora, CentOS, RHEL)" - echo " * csw: $PKG_CSW_NAME (Solaris)" - echo " * brew: $PKG_BREW_NAME (Mac OSX)" - echo "If $PKG_CONFIG_NAME is already installed, check that 'pkg-config' is in your" - echo "PATH and PKG_CONFIG_PATH contains a $PKG_CONFIG_NAME.pc file. If pkg-config" - echo "is unavailable you can set INCLUDE_DIR and LIB_DIR manually via:" - echo "R CMD INSTALL --configure-vars='INCLUDE_DIR=... LIB_DIR=...'" - echo "-------------------------- [ERROR MESSAGE] ---------------------------" - cat configure.log - echo "--------------------------------------------------------------------" - exit 1 -fi - -# Write to Makevars -sed -e "s|@PKG_CXXFLAGS@|$PKG_CFLAGS|" -e "s|@PKG_LIBS@|$PKG_LIBS|" src/Makevars.in > src/Makevars - -# Success -exit 0 diff --git a/src/Makevars b/src/Makevars index f3cae4a92..92da27d01 100644 --- a/src/Makevars +++ b/src/Makevars @@ -1,9 +1,7 @@ -#PKG_CPPFLAGS = -I. -I../inst/include/pugixml -Ixlcpp -DXLCPP_EXPORT PKG_CXXFLAGS = -I. -Ixlcpp -I../inst/include/pugixml -DXLCPP_EXPORT -#PKG_LIBS=-Lpugixml -Lcfbf -L/usr/lib -larchive -L/usr/lib -lfmt -PKG_LIBS = -larchive -Lpugixml -Lxlcpp +PKG_LIBS = -Lpugixml -Lxlcpp PKGROOT = ./xlcpp @@ -15,24 +13,23 @@ OBJECTS = decrypt.o \ styles_xml.o \ write_file.o \ $(PKGROOT)/aes.o \ - $(PKGROOT)/b64.o \ - $(PKGROOT)/cfbf.o \ - $(PKGROOT)/mmap.o \ - $(PKGROOT)/sha1.o \ - $(PKGROOT)/sha512.o \ - $(PKGROOT)/xlcpp.o \ - $(PKGROOT)/xml-reader.o \ - RcppExports.o - + $(PKGROOT)/b64.o \ + $(PKGROOT)/cfbf.o \ + $(PKGROOT)/mmap.o \ + $(PKGROOT)/sha1.o \ + $(PKGROOT)/sha512.o \ + $(PKGROOT)/xlcpp.o \ + $(PKGROOT)/xml-reader.o \ + RcppExports.o XLCPP = $(PKGROOT)/aes.cpp \ - $(PKGROOT)/b64.cpp \ - $(PKGROOT)/cfbf.cpp \ - $(PKGROOT)/mmap.cpp \ - $(PKGROOT)/sha1.cpp \ - $(PKGROOT)/sha512.cpp \ - $(PKGROOT)/xml-reader.cpp \ - $(PKGROOT)/xlcpp.cpp + $(PKGROOT)/b64.cpp \ + $(PKGROOT)/cfbf.cpp \ + $(PKGROOT)/mmap.cpp \ + $(PKGROOT)/sha1.cpp \ + $(PKGROOT)/sha512.cpp \ + $(PKGROOT)/xml-reader.cpp \ + $(PKGROOT)/xlcpp.cpp PUGIXML = ../inst/include/pugixml/pugixml.cpp diff --git a/src/Makevars.in b/src/Makevars.in deleted file mode 100644 index 4da22aace..000000000 --- a/src/Makevars.in +++ /dev/null @@ -1,39 +0,0 @@ - -#PKG_CPPFLAGS = -I. -I../inst/include/pugixml -Ixlcpp -DXLCPP_EXPORT -PKG_CXXFLAGS = @PKG_CXXFLAGS@ -I. -Ixlcpp -I../inst/include/pugixml -DXLCPP_EXPORT - -#PKG_LIBS=-Lpugixml -Lcfbf -L/usr/lib -larchive -L/usr/lib -lfmt -PKG_LIBS = @PKG_LIBS@ -Lpugixml -Lxlcpp - -PKGROOT = ./xlcpp - -OBJECTS = decrypt.o \ - helper_functions.o \ - load_workbook.o \ - pugi.o \ - strings_xml.o \ - styles_xml.o \ - write_file.o \ - $(PKGROOT)/aes.o \ - $(PKGROOT)/b64.o \ - $(PKGROOT)/cfbf.o \ - $(PKGROOT)/mmap.o \ - $(PKGROOT)/sha1.o \ - $(PKGROOT)/sha512.o \ - $(PKGROOT)/xlcpp.o \ - $(PKGROOT)/xml-reader.o \ - RcppExports.o - - -XLCPP = $(PKGROOT)/aes.cpp \ - $(PKGROOT)/b64.cpp \ - $(PKGROOT)/cfbf.cpp \ - $(PKGROOT)/mmap.cpp \ - $(PKGROOT)/sha1.cpp \ - $(PKGROOT)/sha512.cpp \ - $(PKGROOT)/xml-reader.cpp \ - $(PKGROOT)/xlcpp.cpp - -PUGIXML = ../inst/include/pugixml/pugixml.cpp - -# CXX_STD=CXX20 diff --git a/src/xlcpp/xlcpp-pimpl.h b/src/xlcpp/xlcpp-pimpl.h index f3325d12a..c2a3a03c8 100644 --- a/src/xlcpp/xlcpp-pimpl.h +++ b/src/xlcpp/xlcpp-pimpl.h @@ -11,8 +11,8 @@ #include #include #include -#include -#include +// #include +// #include namespace xlcpp { @@ -33,8 +33,8 @@ class workbook_pimpl { workbook_pimpl(std::span sv, std::string_view password, std::string_view outfile); std::string data() const; - void write_archive(struct archive* a) const; - la_ssize_t write_callback(struct archive* a, const void* buffer, size_t length) const; + // void write_archive(struct archive* a) const; + // la_ssize_t write_callback(struct archive* a, const void* buffer, size_t length) const; void load_archive(struct archive* a); #ifdef _WIN32 @@ -53,32 +53,34 @@ class workbook_pimpl { void load_from_memory(std::span sv, std::string_view password, std::string_view outfile); }; +}; // end namespace xlcpp + + enum class xml_node { - unknown, - text, - whitespace, - element, - end_element, - processing_instruction, - comment, - cdata + unknown, + text, + whitespace, + element, + end_element, + processing_instruction, + comment, + cdata }; - class xml_enc_string_view { public: - xml_enc_string_view() { } - xml_enc_string_view(std::string_view sv) : sv(sv) { } + xml_enc_string_view() { } + xml_enc_string_view(std::string_view sv) : sv(sv) { } - bool empty() const noexcept { - return sv.empty(); - } + bool empty() const noexcept { + return sv.empty(); + } - std::string decode() const; - bool cmp(std::string_view str) const; + std::string decode() const; + bool cmp(std::string_view str) const; private: - std::string_view sv; + std::string_view sv; }; using ns_list = std::vector>; @@ -104,24 +106,24 @@ class xml_reader { std::vector namespaces; }; -class archive_read_closer { -public: - typedef archive* pointer; - - void operator()(archive* a) { - archive_read_free(a); - } -}; - -using archive_read_t = std::unique_ptr; - -class archive_write_closer { -public: - typedef archive* pointer; - - void operator()(archive* a) { - archive_write_free(a); - } -}; - -using archive_write_t = std::unique_ptr; +// class archive_read_closer { +// public: +// typedef archive* pointer; +// +// void operator()(archive* a) { +// archive_read_free(a); +// } +// }; +// +// using archive_read_t = std::unique_ptr; +// +// class archive_write_closer { +// public: +// typedef archive* pointer; +// +// void operator()(archive* a) { +// archive_write_free(a); +// } +// }; +// +// using archive_write_t = std::unique_ptr; diff --git a/src/xlcpp/xlcpp.cpp b/src/xlcpp/xlcpp.cpp index 62bfd58a2..da5f831b8 100644 --- a/src/xlcpp/xlcpp.cpp +++ b/src/xlcpp/xlcpp.cpp @@ -7,15 +7,13 @@ #include "mmap.h" #include "cfbf.h" #include "utf16.h" -#include -#include #include #include #include -#ifdef _WIN32 -#include -#endif +// #ifdef _WIN32 +// #include +// #endif // #define FMT_HEADER_ONLY // #include @@ -70,17 +68,17 @@ __inline string utf16_to_utf8(const u16string_view& s) { #endif workbook_pimpl::workbook_pimpl(const filesystem::path& fn, string_view password, string_view outfile) { -#ifdef _WIN32 - unique_handle hup{CreateFileW((LPCWSTR)fn.u16string().c_str(), FILE_READ_DATA | DELETE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, nullptr)}; - if (hup.get() == INVALID_HANDLE_VALUE) - throw last_error("CreateFile", GetLastError()); -#else +// #ifdef _WIN32 +// unique_handle hup{CreateFileW((LPCWSTR)fn.u16string().c_str(), FILE_READ_DATA | DELETE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, +// FILE_ATTRIBUTE_NORMAL, nullptr)}; +// if (hup.get() == INVALID_HANDLE_VALUE) +// throw last_error("CreateFile", GetLastError()); +// #else unique_handle hup{open(fn.string().c_str(), O_RDONLY)}; if (hup.get() == -1) Rcpp::stop("open failed (errno = {})", errno); -#endif +// #endif mmap m(hup.get()); diff --git a/src/xlcpp/xml-reader.cpp b/src/xlcpp/xml-reader.cpp index 4bf09c521..8549af33f 100644 --- a/src/xlcpp/xml-reader.cpp +++ b/src/xlcpp/xml-reader.cpp @@ -336,3 +336,63 @@ static string esc_char(string_view s) { return string{string_view(t, 4)}; } } + +string xml_enc_string_view::decode() const { + auto v = sv; + string s; + + s.reserve(v.length()); + + while (!v.empty()) { + if (v.front() == '&') { + v.remove_prefix(1); + + if (v.starts_with("amp;")) { + s += "&"; + v.remove_prefix(4); + } else if (v.starts_with("lt;")) { + s += "<"; + v.remove_prefix(3); + } else if (v.starts_with("gt;")) { + s += ">"; + v.remove_prefix(3); + } else if (v.starts_with("quot;")) { + s += "\""; + v.remove_prefix(5); + } else if (v.starts_with("apos;")) { + s += "'"; + v.remove_prefix(5); + } else if (v.starts_with("#")) { + string_view bit; + + v.remove_prefix(1); + + auto sc = v.find_first_of(';'); + if (sc == string::npos) { + bit = v; + v = ""; + } else { + bit = v.substr(0, sc); + v.remove_prefix(sc + 1); + } + + s += esc_char(bit); + } else + s += "&"; + } else { + s += v.front(); + v.remove_prefix(1); + } + } + + return s; +} + +bool xml_enc_string_view::cmp(string_view str) const { + for (auto c : sv) { + if (c == '&') + return decode() == str; + } + + return sv == str; +} From 39b180ae000689df6be4473b1f84ee2e8cf3f76b Mon Sep 17 00:00:00 2001 From: Jan Marvin Garbuszus Date: Mon, 17 Jul 2023 00:15:18 +0200 Subject: [PATCH 5/9] build on Mac --- src/xlcpp/cfbf.h | 17 --- src/xlcpp/mmap.cpp | 270 ++++++++++++++++++++++----------------------- 2 files changed, 135 insertions(+), 152 deletions(-) diff --git a/src/xlcpp/cfbf.h b/src/xlcpp/cfbf.h index 732be30c9..20a0f7291 100644 --- a/src/xlcpp/cfbf.h +++ b/src/xlcpp/cfbf.h @@ -7,26 +7,9 @@ #include #include #include -#include -#include static const uint64_t CFBF_SIGNATURE = 0xe11ab1a1e011cfd0; -class _formatted_error : public std::exception { -public: - template - _formatted_error(T&& s, Args&&... args) { - msg = fmt::format(s, std::forward(args)...); - } - - const char* what() const noexcept { - return msg.c_str(); - } - -private: - std::string msg; -}; - #define formatted_error(s, ...) _formatted_error(FMT_COMPILE(s), ##__VA_ARGS__) class cfbf; diff --git a/src/xlcpp/mmap.cpp b/src/xlcpp/mmap.cpp index d2c609c3f..7f0163d1d 100644 --- a/src/xlcpp/mmap.cpp +++ b/src/xlcpp/mmap.cpp @@ -137,54 +137,54 @@ errno_error::errno_error(string_view function, int en) : msg(function) { case EIDRM: msg += "EIDRM"; break; - case ECHRNG: - msg += "ECHRNG"; - break; - case EL2NSYNC: - msg += "EL2NSYNC"; - break; - case EL3HLT: - msg += "EL3HLT"; - break; - case EL3RST: - msg += "EL3RST"; - break; - case ELNRNG: - msg += "ELNRNG"; - break; - case EUNATCH: - msg += "EUNATCH"; - break; - case ENOCSI: - msg += "ENOCSI"; - break; - case EL2HLT: - msg += "EL2HLT"; - break; - case EBADE: - msg += "EBADE"; - break; - case EBADR: - msg += "EBADR"; - break; - case EXFULL: - msg += "EXFULL"; - break; - case ENOANO: - msg += "ENOANO"; - break; - case EBADRQC: - msg += "EBADRQC"; - break; - case EBADSLT: - msg += "EBADSLT"; - break; - case EDEADLOCK: - msg += "EDEADLOCK"; - break; - case EBFONT: - msg += "EBFONT"; - break; + // case ECHRNG: + // msg += "ECHRNG"; + // break; + // case EL2NSYNC: + // msg += "EL2NSYNC"; + // break; + // case EL3HLT: + // msg += "EL3HLT"; + // break; + // case EL3RST: + // msg += "EL3RST"; + // break; + // case ELNRNG: + // msg += "ELNRNG"; + // break; + // case EUNATCH: + // msg += "EUNATCH"; + // break; + // case ENOCSI: + // msg += "ENOCSI"; + // break; + // case EL2HLT: + // msg += "EL2HLT"; + // break; + // case EBADE: + // msg += "EBADE"; + // break; + // case EBADR: + // msg += "EBADR"; + // break; + // case EXFULL: + // msg += "EXFULL"; + // break; + // case ENOANO: + // msg += "ENOANO"; + // break; + // case EBADRQC: + // msg += "EBADRQC"; + // break; + // case EBADSLT: + // msg += "EBADSLT"; + // break; + // case EDEADLOCK: + // msg += "EDEADLOCK"; + // break; + // case EBFONT: + // msg += "EBFONT"; + // break; case ENOSTR: msg += "ENOSTR"; break; @@ -197,75 +197,75 @@ errno_error::errno_error(string_view function, int en) : msg(function) { case ENOSR: msg += "ENOSR"; break; - case ENONET: - msg += "ENONET"; - break; - case ENOPKG: - msg += "ENOPKG"; - break; + // case ENONET: + // msg += "ENONET"; + // break; + // case ENOPKG: + // msg += "ENOPKG"; + // break; case EREMOTE: msg += "EREMOTE"; break; case ENOLINK: msg += "ENOLINK"; break; - case EADV: - msg += "EADV"; - break; - case ESRMNT: - msg += "ESRMNT"; - break; - case ECOMM: - msg += "ECOMM"; - break; + // case EADV: + // msg += "EADV"; + // break; + // case ESRMNT: + // msg += "ESRMNT"; + // break; + // case ECOMM: + // msg += "ECOMM"; + // break; case EPROTO: msg += "EPROTO"; break; case EMULTIHOP: msg += "EMULTIHOP"; break; - case EDOTDOT: - msg += "EDOTDOT"; - break; + // case EDOTDOT: + // msg += "EDOTDOT"; + // break; case EBADMSG: msg += "EBADMSG"; break; case EOVERFLOW: msg += "EOVERFLOW"; break; - case ENOTUNIQ: - msg += "ENOTUNIQ"; - break; - case EBADFD: - msg += "EBADFD"; - break; - case EREMCHG: - msg += "EREMCHG"; - break; - case ELIBACC: - msg += "ELIBACC"; - break; - case ELIBBAD: - msg += "ELIBBAD"; - break; - case ELIBSCN: - msg += "ELIBSCN"; - break; - case ELIBMAX: - msg += "ELIBMAX"; - break; - case ELIBEXEC: - msg += "ELIBEXEC"; - break; + // case ENOTUNIQ: + // msg += "ENOTUNIQ"; + // break; + // case EBADFD: + // msg += "EBADFD"; + // break; + // case EREMCHG: + // msg += "EREMCHG"; + // break; + // case ELIBACC: + // msg += "ELIBACC"; + // break; + // case ELIBBAD: + // msg += "ELIBBAD"; + // break; + // case ELIBSCN: + // msg += "ELIBSCN"; + // break; + // case ELIBMAX: + // msg += "ELIBMAX"; + // break; + // case ELIBEXEC: + // msg += "ELIBEXEC"; + // break; case EILSEQ: msg += "EILSEQ"; break; - case ERESTART: - msg += "ERESTART"; - break; - case ESTRPIPE: - msg += "ESTRPIPE"; - break; + // case ERESTART: + // msg += "ERESTART"; + // break; + // case ESTRPIPE: + // msg += "ESTRPIPE"; + // break; case EUSERS: msg += "EUSERS"; break; @@ -356,57 +356,57 @@ errno_error::errno_error(string_view function, int en) : msg(function) { case ESTALE: msg += "ESTALE"; break; - case EUCLEAN: - msg += "EUCLEAN"; - break; - case ENOTNAM: - msg += "ENOTNAM"; - break; - case ENAVAIL: - msg += "ENAVAIL"; - break; - case EISNAM: - msg += "EISNAM"; - break; - case EREMOTEIO: - msg += "EREMOTEIO"; - break; + // case EUCLEAN: + // msg += "EUCLEAN"; + // break; + // case ENOTNAM: + // msg += "ENOTNAM"; + // break; + // case ENAVAIL: + // msg += "ENAVAIL"; + // break; + // case EISNAM: + // msg += "EISNAM"; + // break; + // case EREMOTEIO: + // msg += "EREMOTEIO"; + // break; case EDQUOT: msg += "EDQUOT"; break; - case ENOMEDIUM: - msg += "ENOMEDIUM"; - break; - case EMEDIUMTYPE: - msg += "EMEDIUMTYPE"; - break; + // case ENOMEDIUM: + // msg += "ENOMEDIUM"; + // break; + // case EMEDIUMTYPE: + // msg += "EMEDIUMTYPE"; + // break; case ECANCELED: msg += "ECANCELED"; break; - case ENOKEY: - msg += "ENOKEY"; - break; - case EKEYEXPIRED: - msg += "EKEYEXPIRED"; - break; - case EKEYREVOKED: - msg += "EKEYREVOKED"; - break; - case EKEYREJECTED: - msg += "EKEYREJECTED"; - break; + // case ENOKEY: + // msg += "ENOKEY"; + // break; + // case EKEYEXPIRED: + // msg += "EKEYEXPIRED"; + // break; + // case EKEYREVOKED: + // msg += "EKEYREVOKED"; + // break; + // case EKEYREJECTED: + // msg += "EKEYREJECTED"; + // break; case EOWNERDEAD: msg += "EOWNERDEAD"; break; case ENOTRECOVERABLE: msg += "ENOTRECOVERABLE"; break; - case ERFKILL: - msg += "ERFKILL"; - break; - case EHWPOISON: - msg += "EHWPOISON"; - break; + // case ERFKILL: + // msg += "ERFKILL"; + // break; + // case EHWPOISON: + // msg += "EHWPOISON"; + // break; default: msg += to_string(en); break; From 0e0db855881f9c009889e46277cb67625b6c5eac Mon Sep 17 00:00:00 2001 From: Jan Marvin Garbuszus Date: Mon, 17 Jul 2023 00:30:15 +0200 Subject: [PATCH 6/9] remove mmap hopefully less platform dependent --- DESCRIPTION | 4 +- R/wb_load.R | 1 + src/Makevars | 2 - src/xlcpp/cfbf.h | 2 - src/xlcpp/mmap.cpp | 472 ---------------------------------------- src/xlcpp/mmap.h | 151 ------------- src/xlcpp/xlcpp-pimpl.h | 25 --- src/xlcpp/xlcpp.cpp | 49 +++-- 8 files changed, 28 insertions(+), 678 deletions(-) delete mode 100644 src/xlcpp/mmap.cpp delete mode 100644 src/xlcpp/mmap.h diff --git a/DESCRIPTION b/DESCRIPTION index 984c1224b..9aab09023 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -43,5 +43,5 @@ Roxygen: list(markdown = TRUE) Config/testthat/edition: 3 Config/testthat/parallel: false Config/testthat/start-first: aaa -SystemRequirements: C++20, libarchive: libarchive-dev (deb), - libarchive-devel (rpm), libarchive (homebrew), libarchive_dev (csw), libfmt: libfmt-dev (deb), fmt (homebrew) +SystemRequirements: C++20 + diff --git a/R/wb_load.R b/R/wb_load.R index 3c2b5681a..b2fe24734 100644 --- a/R/wb_load.R +++ b/R/wb_load.R @@ -40,6 +40,7 @@ wb_load <- function( ... ) { + password <- NULL standardize_case_names(...) file <- xlsx_file %||% file diff --git a/src/Makevars b/src/Makevars index 92da27d01..1056930a6 100644 --- a/src/Makevars +++ b/src/Makevars @@ -15,7 +15,6 @@ OBJECTS = decrypt.o \ $(PKGROOT)/aes.o \ $(PKGROOT)/b64.o \ $(PKGROOT)/cfbf.o \ - $(PKGROOT)/mmap.o \ $(PKGROOT)/sha1.o \ $(PKGROOT)/sha512.o \ $(PKGROOT)/xlcpp.o \ @@ -25,7 +24,6 @@ OBJECTS = decrypt.o \ XLCPP = $(PKGROOT)/aes.cpp \ $(PKGROOT)/b64.cpp \ $(PKGROOT)/cfbf.cpp \ - $(PKGROOT)/mmap.cpp \ $(PKGROOT)/sha1.cpp \ $(PKGROOT)/sha512.cpp \ $(PKGROOT)/xml-reader.cpp \ diff --git a/src/xlcpp/cfbf.h b/src/xlcpp/cfbf.h index 20a0f7291..2100dafeb 100644 --- a/src/xlcpp/cfbf.h +++ b/src/xlcpp/cfbf.h @@ -1,6 +1,5 @@ #pragma once -#include "mmap.h" #include #include #include @@ -51,7 +50,6 @@ class cfbf { const dirent& find_dirent(uint32_t num); std::vector decrypt44(std::span enc_package); - std::unique_ptr m; std::array key; unsigned int key_size; std::array salt; diff --git a/src/xlcpp/mmap.cpp b/src/xlcpp/mmap.cpp deleted file mode 100644 index 7f0163d1d..000000000 --- a/src/xlcpp/mmap.cpp +++ /dev/null @@ -1,472 +0,0 @@ -#include "mmap.h" - -#ifndef _WIN32 -#include -#include -#include -#include -#endif - -using namespace std; - -#ifndef _WIN32 -errno_error::errno_error(string_view function, int en) : msg(function) { - msg += " failed ("; - - switch (en) { - case EPERM: - msg += "EPERM"; - break; - case ENOENT: - msg += "ENOENT"; - break; - case ESRCH: - msg += "ESRCH"; - break; - case EINTR: - msg += "EINTR"; - break; - case EIO: - msg += "EIO"; - break; - case ENXIO: - msg += "ENXIO"; - break; - case E2BIG: - msg += "E2BIG"; - break; - case ENOEXEC: - msg += "ENOEXEC"; - break; - case EBADF: - msg += "EBADF"; - break; - case ECHILD: - msg += "ECHILD"; - break; - case EAGAIN: - msg += "EAGAIN"; - break; - case ENOMEM: - msg += "ENOMEM"; - break; - case EACCES: - msg += "EACCES"; - break; - case EFAULT: - msg += "EFAULT"; - break; - case ENOTBLK: - msg += "ENOTBLK"; - break; - case EBUSY: - msg += "EBUSY"; - break; - case EEXIST: - msg += "EEXIST"; - break; - case EXDEV: - msg += "EXDEV"; - break; - case ENODEV: - msg += "ENODEV"; - break; - case ENOTDIR: - msg += "ENOTDIR"; - break; - case EISDIR: - msg += "EISDIR"; - break; - case EINVAL: - msg += "EINVAL"; - break; - case ENFILE: - msg += "ENFILE"; - break; - case EMFILE: - msg += "EMFILE"; - break; - case ENOTTY: - msg += "ENOTTY"; - break; - case ETXTBSY: - msg += "ETXTBSY"; - break; - case EFBIG: - msg += "EFBIG"; - break; - case ENOSPC: - msg += "ENOSPC"; - break; - case ESPIPE: - msg += "ESPIPE"; - break; - case EROFS: - msg += "EROFS"; - break; - case EMLINK: - msg += "EMLINK"; - break; - case EPIPE: - msg += "EPIPE"; - break; - case EDOM: - msg += "EDOM"; - break; - case ERANGE: - msg += "ERANGE"; - break; - case ENAMETOOLONG: - msg += "ENAMETOOLONG"; - break; - case ENOLCK: - msg += "ENOLCK"; - break; - case ENOSYS: - msg += "ENOSYS"; - break; - case ENOTEMPTY: - msg += "ENOTEMPTY"; - break; - case ELOOP: - msg += "ELOOP"; - break; - case ENOMSG: - msg += "ENOMSG"; - break; - case EIDRM: - msg += "EIDRM"; - break; - // case ECHRNG: - // msg += "ECHRNG"; - // break; - // case EL2NSYNC: - // msg += "EL2NSYNC"; - // break; - // case EL3HLT: - // msg += "EL3HLT"; - // break; - // case EL3RST: - // msg += "EL3RST"; - // break; - // case ELNRNG: - // msg += "ELNRNG"; - // break; - // case EUNATCH: - // msg += "EUNATCH"; - // break; - // case ENOCSI: - // msg += "ENOCSI"; - // break; - // case EL2HLT: - // msg += "EL2HLT"; - // break; - // case EBADE: - // msg += "EBADE"; - // break; - // case EBADR: - // msg += "EBADR"; - // break; - // case EXFULL: - // msg += "EXFULL"; - // break; - // case ENOANO: - // msg += "ENOANO"; - // break; - // case EBADRQC: - // msg += "EBADRQC"; - // break; - // case EBADSLT: - // msg += "EBADSLT"; - // break; - // case EDEADLOCK: - // msg += "EDEADLOCK"; - // break; - // case EBFONT: - // msg += "EBFONT"; - // break; - case ENOSTR: - msg += "ENOSTR"; - break; - case ENODATA: - msg += "ENODATA"; - break; - case ETIME: - msg += "ETIME"; - break; - case ENOSR: - msg += "ENOSR"; - break; - // case ENONET: - // msg += "ENONET"; - // break; - // case ENOPKG: - // msg += "ENOPKG"; - // break; - case EREMOTE: - msg += "EREMOTE"; - break; - case ENOLINK: - msg += "ENOLINK"; - break; - // case EADV: - // msg += "EADV"; - // break; - // case ESRMNT: - // msg += "ESRMNT"; - // break; - // case ECOMM: - // msg += "ECOMM"; - // break; - case EPROTO: - msg += "EPROTO"; - break; - case EMULTIHOP: - msg += "EMULTIHOP"; - break; - // case EDOTDOT: - // msg += "EDOTDOT"; - // break; - case EBADMSG: - msg += "EBADMSG"; - break; - case EOVERFLOW: - msg += "EOVERFLOW"; - break; - // case ENOTUNIQ: - // msg += "ENOTUNIQ"; - // break; - // case EBADFD: - // msg += "EBADFD"; - // break; - // case EREMCHG: - // msg += "EREMCHG"; - // break; - // case ELIBACC: - // msg += "ELIBACC"; - // break; - // case ELIBBAD: - // msg += "ELIBBAD"; - // break; - // case ELIBSCN: - // msg += "ELIBSCN"; - // break; - // case ELIBMAX: - // msg += "ELIBMAX"; - // break; - // case ELIBEXEC: - // msg += "ELIBEXEC"; - // break; - case EILSEQ: - msg += "EILSEQ"; - break; - // case ERESTART: - // msg += "ERESTART"; - // break; - // case ESTRPIPE: - // msg += "ESTRPIPE"; - // break; - case EUSERS: - msg += "EUSERS"; - break; - case ENOTSOCK: - msg += "ENOTSOCK"; - break; - case EDESTADDRREQ: - msg += "EDESTADDRREQ"; - break; - case EMSGSIZE: - msg += "EMSGSIZE"; - break; - case EPROTOTYPE: - msg += "EPROTOTYPE"; - break; - case ENOPROTOOPT: - msg += "ENOPROTOOPT"; - break; - case EPROTONOSUPPORT: - msg += "EPROTONOSUPPORT"; - break; - case ESOCKTNOSUPPORT: - msg += "ESOCKTNOSUPPORT"; - break; - case EOPNOTSUPP: - msg += "EOPNOTSUPP"; - break; - case EPFNOSUPPORT: - msg += "EPFNOSUPPORT"; - break; - case EAFNOSUPPORT: - msg += "EAFNOSUPPORT"; - break; - case EADDRINUSE: - msg += "EADDRINUSE"; - break; - case EADDRNOTAVAIL: - msg += "EADDRNOTAVAIL"; - break; - case ENETDOWN: - msg += "ENETDOWN"; - break; - case ENETUNREACH: - msg += "ENETUNREACH"; - break; - case ENETRESET: - msg += "ENETRESET"; - break; - case ECONNABORTED: - msg += "ECONNABORTED"; - break; - case ECONNRESET: - msg += "ECONNRESET"; - break; - case ENOBUFS: - msg += "ENOBUFS"; - break; - case EISCONN: - msg += "EISCONN"; - break; - case ENOTCONN: - msg += "ENOTCONN"; - break; - case ESHUTDOWN: - msg += "ESHUTDOWN"; - break; - case ETOOMANYREFS: - msg += "ETOOMANYREFS"; - break; - case ETIMEDOUT: - msg += "ETIMEDOUT"; - break; - case ECONNREFUSED: - msg += "ECONNREFUSED"; - break; - case EHOSTDOWN: - msg += "EHOSTDOWN"; - break; - case EHOSTUNREACH: - msg += "EHOSTUNREACH"; - break; - case EALREADY: - msg += "EALREADY"; - break; - case EINPROGRESS: - msg += "EINPROGRESS"; - break; - case ESTALE: - msg += "ESTALE"; - break; - // case EUCLEAN: - // msg += "EUCLEAN"; - // break; - // case ENOTNAM: - // msg += "ENOTNAM"; - // break; - // case ENAVAIL: - // msg += "ENAVAIL"; - // break; - // case EISNAM: - // msg += "EISNAM"; - // break; - // case EREMOTEIO: - // msg += "EREMOTEIO"; - // break; - case EDQUOT: - msg += "EDQUOT"; - break; - // case ENOMEDIUM: - // msg += "ENOMEDIUM"; - // break; - // case EMEDIUMTYPE: - // msg += "EMEDIUMTYPE"; - // break; - case ECANCELED: - msg += "ECANCELED"; - break; - // case ENOKEY: - // msg += "ENOKEY"; - // break; - // case EKEYEXPIRED: - // msg += "EKEYEXPIRED"; - // break; - // case EKEYREVOKED: - // msg += "EKEYREVOKED"; - // break; - // case EKEYREJECTED: - // msg += "EKEYREJECTED"; - // break; - case EOWNERDEAD: - msg += "EOWNERDEAD"; - break; - case ENOTRECOVERABLE: - msg += "ENOTRECOVERABLE"; - break; - // case ERFKILL: - // msg += "ERFKILL"; - // break; - // case EHWPOISON: - // msg += "EHWPOISON"; - // break; - default: - msg += to_string(en); - break; - } - - msg += ")"; -} -#endif - -mmap::mmap(fd_t h) { -#ifdef _WIN32 - LARGE_INTEGER fsli; - - if (!GetFileSizeEx(h, &fsli)) - throw last_error("GetFileSizeEx", GetLastError()); - - filesize = fsli.QuadPart; - - mh = CreateFileMappingW(h, nullptr, PAGE_READONLY, 0, 0, nullptr); - if (!mh) - throw last_error("CreateFileMapping", GetLastError()); -#else - struct stat st; - - if (fstat(h, &st) == -1) - throw errno_error("fstat", errno); - - filesize = st.st_size; - - ptr = ::mmap(nullptr, filesize, PROT_READ, MAP_SHARED, h, 0); - - if (ptr == MAP_FAILED) - throw errno_error("mmap", errno); -#endif -} - -mmap::~mmap() { -#ifdef _WIN32 - if (ptr) - UnmapViewOfFile(ptr); - - if (mh) - CloseHandle(mh); - - if (h != INVALID_HANDLE_VALUE) - CloseHandle(h); -#else - munmap(ptr, filesize); -#endif -} - -span mmap::map() { -#ifdef _WIN32 - if (!ptr) { - ptr = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, 0); - - if (!ptr) - throw last_error("MapViewOfFile", GetLastError()); - } -#endif - - return span((const uint8_t*)ptr, filesize); -} diff --git a/src/xlcpp/mmap.h b/src/xlcpp/mmap.h deleted file mode 100644 index 9750e6b8a..000000000 --- a/src/xlcpp/mmap.h +++ /dev/null @@ -1,151 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#include "utf16.h" -using fd_t = HANDLE; -#else -#include -using fd_t = int; -#endif - -#ifdef _WIN32 -class last_error : public std::exception { -public: - last_error(std::string_view function, int le) { - std::string nice_msg; - - { - char16_t* fm; - - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, - le, 0, reinterpret_cast(&fm), 0, nullptr)) { - try { - std::u16string_view s = fm; - - while (!s.empty() && (s[s.length() - 1] == u'\r' || s[s.length() - 1] == u'\n')) { - s.remove_suffix(1); - } - - nice_msg = utf16_to_utf8(s); - } catch (...) { - LocalFree(fm); - throw; - } - - LocalFree(fm); - } - } - - msg = std::string(function) + " failed (error " + std::to_string(le) + (!nice_msg.empty() ? (", " + nice_msg) : "") + ")."; - } - - const char* what() const noexcept { - return msg.c_str(); - } - -private: - std::string msg; -}; -#endif - -#ifdef _WIN32 - -class handle_closer { -public: - typedef HANDLE pointer; - - void operator()(HANDLE h) { - if (h == INVALID_HANDLE_VALUE) - return; - - CloseHandle(h); - } -}; - -using unique_handle = std::unique_ptr; - -#else - -class unique_handle { -public: - unique_handle() : fd(0) { - } - - explicit unique_handle(int fd) : fd(fd) { - } - - unique_handle(unique_handle&& that) noexcept { - fd = that.fd; - that.fd = 0; - } - - unique_handle(const unique_handle&) = delete; - unique_handle& operator=(const unique_handle&) = delete; - - unique_handle& operator=(unique_handle&& that) noexcept { - if (fd > 0) - close(fd); - - fd = that.fd; - that.fd = 0; - - return *this; - } - - ~unique_handle() { - if (fd <= 0) - return; - - close(fd); - } - - void reset(int new_fd) noexcept { - if (fd > 0) - close(fd); - - fd = new_fd; - } - - int get() const noexcept { - return fd; - } - -private: - int fd; -}; -#endif - -class errno_error : public std::exception { -public: - errno_error(std::string_view function, int en); - - const char* what() const noexcept { - return msg.c_str(); - } - -private: - std::string msg; -}; - -class mmap { -public: - explicit mmap(fd_t h); - ~mmap(); - std::span map(); - - size_t filesize; - -private: -#ifdef _WIN32 - HANDLE h = INVALID_HANDLE_VALUE; - HANDLE mh = INVALID_HANDLE_VALUE; -#endif - void* ptr = nullptr; -}; diff --git a/src/xlcpp/xlcpp-pimpl.h b/src/xlcpp/xlcpp-pimpl.h index c2a3a03c8..20e042764 100644 --- a/src/xlcpp/xlcpp-pimpl.h +++ b/src/xlcpp/xlcpp-pimpl.h @@ -1,7 +1,6 @@ #pragma once #include "xlcpp.h" -#include "mmap.h" #include #include #include @@ -11,8 +10,6 @@ #include #include #include -// #include -// #include namespace xlcpp { @@ -105,25 +102,3 @@ class xml_reader { bool empty_tag; std::vector namespaces; }; - -// class archive_read_closer { -// public: -// typedef archive* pointer; -// -// void operator()(archive* a) { -// archive_read_free(a); -// } -// }; -// -// using archive_read_t = std::unique_ptr; -// -// class archive_write_closer { -// public: -// typedef archive* pointer; -// -// void operator()(archive* a) { -// archive_write_free(a); -// } -// }; -// -// using archive_write_t = std::unique_ptr; diff --git a/src/xlcpp/xlcpp.cpp b/src/xlcpp/xlcpp.cpp index da5f831b8..7ec5090c1 100644 --- a/src/xlcpp/xlcpp.cpp +++ b/src/xlcpp/xlcpp.cpp @@ -1,10 +1,9 @@ #include "openxlsx2.h" -#include -#include +#include +#include #include "xlcpp.h" #include "xlcpp-pimpl.h" -#include "mmap.h" #include "cfbf.h" #include "utf16.h" #include @@ -67,22 +66,29 @@ __inline string utf16_to_utf8(const u16string_view& s) { } #endif +std::vector loadFile(const std::string& filename) { + std::ifstream file(filename, std::ios::binary | std::ios::ate); + if (!file.is_open()) { + Rcpp::stop("Failed to open file"); + } + + std::streamsize fileSize = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector buffer(fileSize); + if (file.read(const_cast(reinterpret_cast(buffer.data())), fileSize)) { + return buffer; + } else { + Rcpp::stop("Failed to read file"); + } +} + + workbook_pimpl::workbook_pimpl(const filesystem::path& fn, string_view password, string_view outfile) { -// #ifdef _WIN32 -// unique_handle hup{CreateFileW((LPCWSTR)fn.u16string().c_str(), FILE_READ_DATA | DELETE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, -// FILE_ATTRIBUTE_NORMAL, nullptr)}; -// if (hup.get() == INVALID_HANDLE_VALUE) -// throw last_error("CreateFile", GetLastError()); -// #else - unique_handle hup{open(fn.string().c_str(), O_RDONLY)}; - - if (hup.get() == -1) - Rcpp::stop("open failed (errno = {})", errno); -// #endif - mmap m(hup.get()); + std::string path = fn; - auto mem = m.map(); + std::vector mem = loadFile(path); load_from_memory(mem, password, outfile); } @@ -94,6 +100,7 @@ workbook_pimpl::workbook_pimpl(span sv, string_view password, str void workbook_pimpl::load_from_memory(span mem, string_view password, string_view outfile) { vector plaintext; + std::ofstream xlsx((std::string)outfile, ios::out | ios::binary); if (mem.size() >= sizeof(uint64_t) && *(uint64_t*)mem.data() == CFBF_SIGNATURE) { cfbf c(mem); string enc_info, enc_package; @@ -135,16 +142,10 @@ void workbook_pimpl::load_from_memory(span mem, string_view passw c.parse_enc_info(span((uint8_t*)enc_info.data(), enc_info.size()), u16password); plaintext = c.decrypt(span((uint8_t*)enc_package.data(), enc_package.size())); - mem = plaintext; + xlsx.write((char *) plaintext.data(), plaintext.size()); } + xlsx.close(); - // FIXME I'm to stupid to write the file with libarchive - - if (outfile.compare("") != 0) { - std::ofstream xlsx((std::string)outfile, ios::out | ios::binary); - xlsx.write((char *) mem.data(), mem.size()); - xlsx.close(); - } } workbook::workbook(const filesystem::path& fn, std::string_view password, std::string_view outfile) { From cf527cbe569e471c061cc4737d549f5837c310b9 Mon Sep 17 00:00:00 2001 From: Jan Marvin Garbuszus Date: Mon, 17 Jul 2023 00:41:48 +0200 Subject: [PATCH 7/9] pedantic --- src/xlcpp/cfbf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xlcpp/cfbf.cpp b/src/xlcpp/cfbf.cpp index 4811f05b2..2729c189b 100644 --- a/src/xlcpp/cfbf.cpp +++ b/src/xlcpp/cfbf.cpp @@ -356,7 +356,7 @@ struct encryption_header { uint32_t provider_type; uint32_t reserved1; uint32_t reserved2; - char16_t csp_name[0]; + char16_t csp_name; }; #pragma pack(pop) From 6de832b82b5546fe14c71a7a6ea4934ae942e26d Mon Sep 17 00:00:00 2001 From: Jan Marvin Garbuszus Date: Mon, 17 Jul 2023 00:41:48 +0200 Subject: [PATCH 8/9] pedantic --- src/xlcpp/cfbf.cpp | 2 +- src/xlcpp/xlcpp-pimpl.h | 4 ++-- src/xlcpp/xlcpp.cpp | 14 +++++++------- src/xlcpp/xlcpp.h | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/xlcpp/cfbf.cpp b/src/xlcpp/cfbf.cpp index 4811f05b2..2729c189b 100644 --- a/src/xlcpp/cfbf.cpp +++ b/src/xlcpp/cfbf.cpp @@ -356,7 +356,7 @@ struct encryption_header { uint32_t provider_type; uint32_t reserved1; uint32_t reserved2; - char16_t csp_name[0]; + char16_t csp_name; }; #pragma pack(pop) diff --git a/src/xlcpp/xlcpp-pimpl.h b/src/xlcpp/xlcpp-pimpl.h index 20e042764..39431b29e 100644 --- a/src/xlcpp/xlcpp-pimpl.h +++ b/src/xlcpp/xlcpp-pimpl.h @@ -27,7 +27,7 @@ class workbook_pimpl { public: workbook_pimpl() = default; workbook_pimpl(const std::filesystem::path& fn, std::string_view password, std::string_view outfile); - workbook_pimpl(std::span sv, std::string_view password, std::string_view outfile); + workbook_pimpl(std::span sv, std::string_view password, std::string_view outfile); std::string data() const; // void write_archive(struct archive* a) const; @@ -47,7 +47,7 @@ class workbook_pimpl { #endif private: - void load_from_memory(std::span sv, std::string_view password, std::string_view outfile); + void load_from_memory(std::span sv, std::string_view password, std::string_view outfile); }; }; // end namespace xlcpp diff --git a/src/xlcpp/xlcpp.cpp b/src/xlcpp/xlcpp.cpp index 7ec5090c1..50bc5d72a 100644 --- a/src/xlcpp/xlcpp.cpp +++ b/src/xlcpp/xlcpp.cpp @@ -66,7 +66,7 @@ __inline string utf16_to_utf8(const u16string_view& s) { } #endif -std::vector loadFile(const std::string& filename) { +std::vector loadFile(const std::string& filename) { std::ifstream file(filename, std::ios::binary | std::ios::ate); if (!file.is_open()) { Rcpp::stop("Failed to open file"); @@ -75,8 +75,8 @@ std::vector loadFile(const std::string& filename) { std::streamsize fileSize = file.tellg(); file.seekg(0, std::ios::beg); - std::vector buffer(fileSize); - if (file.read(const_cast(reinterpret_cast(buffer.data())), fileSize)) { + std::vector buffer(fileSize); + if (file.read(reinterpret_cast(buffer.data()), fileSize)) { return buffer; } else { Rcpp::stop("Failed to read file"); @@ -88,16 +88,16 @@ workbook_pimpl::workbook_pimpl(const filesystem::path& fn, string_view password, std::string path = fn; - std::vector mem = loadFile(path); + std::vector mem = loadFile(path); load_from_memory(mem, password, outfile); } -workbook_pimpl::workbook_pimpl(span sv, string_view password, string_view outfile) { +workbook_pimpl::workbook_pimpl(span sv, string_view password, string_view outfile) { load_from_memory(sv, password, outfile); } -void workbook_pimpl::load_from_memory(span mem, string_view password, string_view outfile) { +void workbook_pimpl::load_from_memory(span mem, string_view password, string_view outfile) { vector plaintext; std::ofstream xlsx((std::string)outfile, ios::out | ios::binary); @@ -152,7 +152,7 @@ workbook::workbook(const filesystem::path& fn, std::string_view password, std::s impl = new workbook_pimpl(fn, password, outfile); } -workbook::workbook(span sv, std::string_view password, std::string_view outfile) { +workbook::workbook(span sv, std::string_view password, std::string_view outfile) { impl = new workbook_pimpl(sv, password, outfile); } diff --git a/src/xlcpp/xlcpp.h b/src/xlcpp/xlcpp.h index 49c2b84a9..95f5b34bd 100644 --- a/src/xlcpp/xlcpp.h +++ b/src/xlcpp/xlcpp.h @@ -40,7 +40,7 @@ class XLCPP workbook { public: workbook(); workbook(const std::filesystem::path& fn, std::string_view password = "", std::string_view outfile = ""); - workbook(std::span sv, std::string_view password = "", std::string_view outfile = ""); + workbook(std::span sv, std::string_view password = "", std::string_view outfile = ""); ~workbook(); workbook_pimpl* impl; From 33b30b5e35e385236320c1aaaef97652b8ac5663 Mon Sep 17 00:00:00 2001 From: Jan Marvin Garbuszus Date: Mon, 17 Jul 2023 01:01:40 +0200 Subject: [PATCH 9/9] windows --- src/decrypt.cpp | 3 +-- src/xlcpp/cfbf.h | 2 +- src/xlcpp/xlcpp-pimpl.h | 14 +------------- src/xlcpp/xlcpp.cpp | 21 +++++---------------- src/xlcpp/xlcpp.h | 4 ++-- 5 files changed, 10 insertions(+), 34 deletions(-) diff --git a/src/decrypt.cpp b/src/decrypt.cpp index e0de3cd74..6063624e9 100644 --- a/src/decrypt.cpp +++ b/src/decrypt.cpp @@ -3,9 +3,8 @@ // [[Rcpp::export]] void read_encryption(std::string PATH, std::string OUT, std::string PASSWORD) { - const std::filesystem::path path = PATH; - xlcpp::workbook wb(path, PASSWORD, OUT); + xlcpp::workbook wb(PATH, PASSWORD, OUT); // this creates xlcpp workbook, not the unzipped xlsx file // wb.save(OUT); diff --git a/src/xlcpp/cfbf.h b/src/xlcpp/cfbf.h index 2100dafeb..1d309bd6c 100644 --- a/src/xlcpp/cfbf.h +++ b/src/xlcpp/cfbf.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/xlcpp/xlcpp-pimpl.h b/src/xlcpp/xlcpp-pimpl.h index 39431b29e..47e2e3f47 100644 --- a/src/xlcpp/xlcpp-pimpl.h +++ b/src/xlcpp/xlcpp-pimpl.h @@ -26,7 +26,7 @@ typedef struct { class workbook_pimpl { public: workbook_pimpl() = default; - workbook_pimpl(const std::filesystem::path& fn, std::string_view password, std::string_view outfile); + workbook_pimpl(std::string& fn, std::string_view password, std::string_view outfile); workbook_pimpl(std::span sv, std::string_view password, std::string_view outfile); std::string data() const; @@ -34,18 +34,6 @@ class workbook_pimpl { // la_ssize_t write_callback(struct archive* a, const void* buffer, size_t length) const; void load_archive(struct archive* a); -#ifdef _WIN32 - void rename(const std::filesystem::path& fn) const; -#endif - - mutable std::string buf; - -#ifdef _WIN32 - unique_handle h; - HANDLE h2; - uint8_t readbuf[1048576]; -#endif - private: void load_from_memory(std::span sv, std::string_view password, std::string_view outfile); }; diff --git a/src/xlcpp/xlcpp.cpp b/src/xlcpp/xlcpp.cpp index 50bc5d72a..27bcd039f 100644 --- a/src/xlcpp/xlcpp.cpp +++ b/src/xlcpp/xlcpp.cpp @@ -10,13 +10,10 @@ #include #include -// #ifdef _WIN32 +#ifdef _WIN32 +#include // #include -// #endif - -// #define FMT_HEADER_ONLY -// #include -// #include +#endif #define BLOCK_SIZE 20480 @@ -31,13 +28,6 @@ static const string NS_CONTENT_TYPES = "http://schemas.openxmlformats.org/packag #define NUMFMT_OFFSET 165 -// static string try_decode(const optional& sv) { -// if (!sv) -// return ""; -// -// return sv.value().decode(); -// } - namespace xlcpp { /* needed??? */ @@ -83,8 +73,7 @@ std::vector loadFile(const std::string& filename) { } } - -workbook_pimpl::workbook_pimpl(const filesystem::path& fn, string_view password, string_view outfile) { +workbook_pimpl::workbook_pimpl(string& fn, string_view password, string_view outfile) { std::string path = fn; @@ -148,7 +137,7 @@ void workbook_pimpl::load_from_memory(span mem, string_view password, s } -workbook::workbook(const filesystem::path& fn, std::string_view password, std::string_view outfile) { +workbook::workbook(string& fn, std::string_view password, std::string_view outfile) { impl = new workbook_pimpl(fn, password, outfile); } diff --git a/src/xlcpp/xlcpp.h b/src/xlcpp/xlcpp.h index 95f5b34bd..aee441495 100644 --- a/src/xlcpp/xlcpp.h +++ b/src/xlcpp/xlcpp.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include @@ -39,7 +39,7 @@ class sheet; class XLCPP workbook { public: workbook(); - workbook(const std::filesystem::path& fn, std::string_view password = "", std::string_view outfile = ""); + workbook(std::string& fn, std::string_view password = "", std::string_view outfile = ""); workbook(std::span sv, std::string_view password = "", std::string_view outfile = ""); ~workbook();