mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-12 10:03:51 +00:00
* Add craft-sheet: the cell positions, values and tables the spreadsheet formats share craft-xls carried its own CellRef, Range, Value, CellError, Visibility, sheet-name quoting, built-in number format table and indexed palette. craft-xlsx and craft-ods need the same ones, so they move to a crate with no dependencies and craft-xls re-exports them: an application gets one Value and one CellRef whichever file it read. Added on the way: A1 parsing (CellRef::parse, Range::parse), Range::count and a1, CellError::parse and the newer error values SpreadsheetML stores as text, builtin_format_id for writers. * Add craft-xlsx: the part layer of XLSX and XLSB workbooks Package::open finds the workbook part through craft-opc and reads the workbook part, shared strings (runs and phonetic readings), the styles tables as indexed tables, and a worksheet's rows one at a time with the rest of the part as a tree. Binary workbooks give the same workbook, strings, rows and merged cells from their records. Every other part stays reachable through Package::opc. From GridCraft crates/xlsx (7e0d96d7): read.rs, sheet_read.rs, styles.rs, xml.rs (string items, xstring escapes), xlsb.rs and its tests, split from GridCraft's document model. * craft-xlsx: XLSB opens up to 4 million cells, records counted once over the workbook Binary workbooks over 1 million cells were refused, a quarter of what .xls allows, and an allowance of 5 million records per part refused ordinary files: Excel writes four records per non-empty row besides the cells, and one BrtCellBlank for every formatted empty cell. Cells are now 4 million over the workbook (also the most shared strings), text 256 MiB, and records 40 million for every part together, as in craft-xls. Ported from storytold/gridcraft#3807. --------- Co-authored-by: kiwi4boy <kiwi4boy@gmail.com>
58 lines
1.7 KiB
Rust
58 lines
1.7 KiB
Rust
//! A whole workbook read through the part layer, for assertions.
|
|
#![allow(dead_code)]
|
|
|
|
use std::collections::BTreeMap;
|
|
|
|
use craft_xlsx::{CellRef, Error, Limits, Package, Range, SheetKind, Value, Visibility};
|
|
|
|
pub struct Sheet {
|
|
pub name: String,
|
|
pub visibility: Visibility,
|
|
pub cells: BTreeMap<CellRef, Value>,
|
|
pub merges: Vec<Range>,
|
|
}
|
|
|
|
impl Sheet {
|
|
pub fn value(&self, at: CellRef) -> Value {
|
|
self.cells.get(&at).cloned().unwrap_or_default()
|
|
}
|
|
}
|
|
|
|
pub struct Book {
|
|
pub date_1904: bool,
|
|
pub sheets: Vec<Sheet>,
|
|
pub skipped: Vec<(String, SheetKind)>,
|
|
pub warnings: Vec<String>,
|
|
}
|
|
|
|
/// Reads every worksheet; cells with no value are left out.
|
|
pub fn read_with(bytes: &[u8], limits: &Limits) -> Result<Book, Error> {
|
|
let mut p = Package::open(bytes, limits)?;
|
|
let wb = p.workbook()?;
|
|
let strings = p.shared_strings()?;
|
|
let mut book = Book { date_1904: wb.date_1904, sheets: vec![], skipped: vec![], warnings: vec![] };
|
|
for e in &wb.sheets {
|
|
if e.kind != SheetKind::Worksheet {
|
|
book.skipped.push((e.name.clone(), e.kind.clone()));
|
|
continue;
|
|
}
|
|
let mut cells = BTreeMap::new();
|
|
let part = p.sheet(e, |row| {
|
|
for c in row.cells {
|
|
let v = c.value.resolve(&strings, wb.date_1904);
|
|
if !v.is_empty() {
|
|
cells.insert(c.at, v);
|
|
}
|
|
}
|
|
Ok(())
|
|
})?;
|
|
book.sheets.push(Sheet { name: e.name.clone(), visibility: e.visibility, cells, merges: part.merges });
|
|
}
|
|
book.warnings = p.warnings().to_vec();
|
|
Ok(book)
|
|
}
|
|
|
|
pub fn read(bytes: &[u8]) -> Result<Book, Error> {
|
|
read_with(bytes, &Limits::default())
|
|
}
|