Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
strategy:
matrix:
toolchain:
- "1.60.0" # MSRV
- "1.63" # MSRV
- stable
- beta
- nightly
Expand Down
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ readme = "README.md"
keywords = ["excel", "ods", "xls", "xlsx", "xlsb"]
categories = ["encoding", "parsing", "text-processing"]
exclude = ["tests/**/*"]
edition = "2018"
rust-version = "1.60"
edition = "2021"
rust-version = "1.63"

[dependencies]
byteorder = "1.4"
Expand All @@ -20,17 +20,17 @@ encoding_rs = "0.8"
log = "0.4"
once_cell = { version = "1.18", optional = true }
serde = "1.0"
quick-xml = { version = "0.29", features = ["encoding"] }
quick-xml = { version = "0.30", features = ["encoding"] }
zip = { version = "0.6", default-features = false, features = ["deflate"] }
chrono = { version = "0.4", features = [
"serde",
], optional = true, default-features = false }

[dev-dependencies]
glob = "0.3"
env_logger = "0.9"
env_logger = "0.10"
serde_derive = "1.0"
sha256 = "1.2"
sha256 = "1.3"

[features]
default = []
Expand Down
9 changes: 2 additions & 7 deletions src/datatype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const MS_MULTIPLIER: f64 = 24f64 * 60f64 * 60f64 * 1e+3f64;

/// An enum to represent all different data types that can appear as
/// a value in a worksheet cell
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Default)]
pub enum DataType {
/// Signed integer
Int(i64),
Expand All @@ -36,15 +36,10 @@ pub enum DataType {
/// Error
Error(CellErrorType),
/// Empty cell
#[default]
Empty,
}

impl Default for DataType {
fn default() -> DataType {
DataType::Empty
}
}

impl DataType {
/// Assess if datatype is empty
pub fn is_empty(&self) -> bool {
Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,8 @@ impl<T: CellType> Range<T> {
pub fn get(&self, relative_position: (usize, usize)) -> Option<&T> {
let (row, col) = relative_position;
let (height, width) = self.get_size();
if col >= height { // row is checked implicitly
if col >= height {
// row is checked implicitly
None
} else {
self.inner.get(row * width + col)
Expand Down
65 changes: 26 additions & 39 deletions src/xls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,30 +291,25 @@ impl<RS: Read + Seek> Xls<RS> {
}
// FORMATTING
0x041E => {
let (idx, format) = parse_format(&mut r, &mut encoding)?;
let (idx, format) = parse_format(&mut r, &encoding)?;
formats.insert(idx, format);
}
// XFS
0x00E0 => {
xfs.push(parse_xf(&mut r)?);
xfs.push(parse_xf(&r)?);
}
// RRTabId
0x0085 => {
let (pos, sheet) = parse_sheet_metadata(&mut r, &mut encoding)?;
let (pos, sheet) = parse_sheet_metadata(&mut r, &encoding)?;
self.metadata.sheets.push(sheet.clone());
sheet_names.push((pos, sheet.name)); // BoundSheet8
}
0x0018 => {
// Lbl for defined_names
let mut cch = r.data[3] as usize;
let cch = r.data[3] as usize;
let cce = read_u16(&r.data[4..]) as usize;
let mut name = String::new();
read_unicode_string_no_cch(
&mut encoding,
&r.data[14..],
&mut cch,
&mut name,
);
read_unicode_string_no_cch(&encoding, &r.data[14..], &cch, &mut name);
let rgce = &r.data[r.data.len() - cce..];
let formula = parse_defined_names(rgce)?;
defined_names.push((name, formula));
Expand All @@ -328,7 +323,7 @@ impl<RS: Read + Seek> Xls<RS> {
_itab_last: read_i16(&xti[4..]),
}));
}
0x00FC => strings = parse_sst(&mut r, &mut encoding)?, // SST
0x00FC => strings = parse_sst(&mut r, &encoding)?, // SST
#[cfg(feature = "picture")]
0x00EB => {
// MsoDrawingGroup
Expand Down Expand Up @@ -395,7 +390,7 @@ impl<RS: Read + Seek> Xls<RS> {
0x0205 => cells.push(parse_bool_err(r.data)?), // 517: BoolErr
0x0207 => {
// 519 String (formula value)
let val = DataType::String(parse_string(r.data, &mut encoding)?);
let val = DataType::String(parse_string(r.data, &encoding)?);
cells.push(Cell::new(fmla_pos, val))
}
0x027E => cells.push(parse_rk(r.data, &self.formats, self.is_1904)?), // 638: Rk
Expand Down Expand Up @@ -424,7 +419,7 @@ impl<RS: Read + Seek> Xls<RS> {
&fmla_sheet_names,
&defined_names,
&xtis,
&mut encoding,
&encoding,
)
.unwrap_or_else(|e| {
debug!("{}", e);
Expand Down Expand Up @@ -462,7 +457,7 @@ impl<RS: Read + Seek> Xls<RS> {
/// BoundSheet8 [MS-XLS 2.4.28]
fn parse_sheet_metadata(
r: &mut Record<'_>,
encoding: &mut XlsEncoding,
encoding: &XlsEncoding,
) -> Result<(usize, Sheet), XlsError> {
let pos = read_u32(r.data) as usize;
let visible = match r.data[4] & 0b0011_1111 {
Expand Down Expand Up @@ -632,7 +627,7 @@ fn rk_num(rk: &[u8], formats: &[CellFormat], is_1904: bool) -> DataType {
}

/// ShortXLUnicodeString [MS-XLS 2.5.240]
fn parse_short_string(r: &mut Record<'_>, encoding: &mut XlsEncoding) -> Result<String, XlsError> {
fn parse_short_string(r: &mut Record<'_>, encoding: &XlsEncoding) -> Result<String, XlsError> {
if r.data.len() < 2 {
return Err(XlsError::Len {
typ: "short string",
Expand All @@ -649,7 +644,7 @@ fn parse_short_string(r: &mut Record<'_>, encoding: &mut XlsEncoding) -> Result<
}

/// XLUnicodeString [MS-XLS 2.5.294]
fn parse_string(r: &[u8], encoding: &mut XlsEncoding) -> Result<String, XlsError> {
fn parse_string(r: &[u8], encoding: &XlsEncoding) -> Result<String, XlsError> {
if r.len() < 2 {
return Err(XlsError::Len {
typ: "short string",
Expand Down Expand Up @@ -726,7 +721,7 @@ fn parse_dimensions(r: &[u8]) -> Result<Dimensions, XlsError> {
}
}

fn parse_sst(r: &mut Record<'_>, encoding: &mut XlsEncoding) -> Result<Vec<String>, XlsError> {
fn parse_sst(r: &mut Record<'_>, encoding: &XlsEncoding) -> Result<Vec<String>, XlsError> {
if r.data.len() < 8 {
return Err(XlsError::Len {
typ: "sst",
Expand All @@ -747,7 +742,7 @@ fn parse_sst(r: &mut Record<'_>, encoding: &mut XlsEncoding) -> Result<Vec<Strin
/// Decode XF (extract only ifmt - Format identifier)
///
/// See: https://learn.microsoft.com/ru-ru/openspecs/office_file_formats/ms-xls/993d15c4-ec04-43e9-ba36-594dfb336c6d
fn parse_xf(r: &mut Record<'_>) -> Result<u16, XlsError> {
fn parse_xf(r: &Record<'_>) -> Result<u16, XlsError> {
if r.data.len() < 4 {
return Err(XlsError::Len {
typ: "xf",
Expand All @@ -762,10 +757,7 @@ fn parse_xf(r: &mut Record<'_>) -> Result<u16, XlsError> {
/// Decode Format
///
/// See: https://learn.microsoft.com/ru-ru/openspecs/office_file_formats/ms-xls/300280fd-e4fe-4675-a924-4d383af48d3b
fn parse_format(
r: &mut Record<'_>,
encoding: &mut XlsEncoding,
) -> Result<(u16, CellFormat), XlsError> {
fn parse_format(r: &mut Record<'_>, encoding: &XlsEncoding) -> Result<(u16, CellFormat), XlsError> {
if r.data.len() < 4 {
return Err(XlsError::Len {
typ: "format",
Expand All @@ -790,7 +782,7 @@ fn parse_format(
/// See: <https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-xls/173d9f51-e5d3-43da-8de2-be7f22e119b9>
fn read_rich_extended_string(
r: &mut Record<'_>,
encoding: &mut XlsEncoding,
encoding: &XlsEncoding,
) -> Result<String, XlsError> {
if r.data.is_empty() && !r.continue_record() || r.data.len() < 3 {
return Err(XlsError::Len {
Expand Down Expand Up @@ -838,7 +830,7 @@ fn read_rich_extended_string(
}

fn read_dbcs(
encoding: &mut XlsEncoding,
encoding: &XlsEncoding,
mut len: usize,
r: &mut Record<'_>,
mut high_byte: bool,
Expand All @@ -860,12 +852,7 @@ fn read_dbcs(
Ok(s)
}

fn read_unicode_string_no_cch(
encoding: &mut XlsEncoding,
buf: &[u8],
len: &mut usize,
s: &mut String,
) {
fn read_unicode_string_no_cch(encoding: &XlsEncoding, buf: &[u8], len: &usize, s: &mut String) {
encoding.decode_to(&buf[1..=*len], *len, s, Some(buf[0] & 0x1 != 0));
}

Expand Down Expand Up @@ -1007,7 +994,7 @@ fn parse_formula(
sheets: &[String],
names: &[(String, String)],
xtis: &[Xti],
encoding: &mut XlsEncoding,
encoding: &XlsEncoding,
) -> Result<String, XlsError> {
let mut stack = Vec::new();
let mut formula = String::with_capacity(rgce.len());
Expand All @@ -1025,7 +1012,7 @@ fn parse_formula(
let sh = xtis
.get(ixti as usize)
.and_then(|xti| sheets.get(xti.itab_first as usize))
.map_or("#REF", |sh| &sh);
.map_or("#REF", |sh| sh);
stack.push(formula.len());
formula.push_str(sh);
formula.push('!');
Expand Down Expand Up @@ -1125,8 +1112,8 @@ fn parse_formula(
0x17 => {
stack.push(formula.len());
formula.push('\"');
let mut cch = rgce[0] as usize;
read_unicode_string_no_cch(encoding, &rgce[1..], &mut cch, &mut formula);
let cch = rgce[0] as usize;
read_unicode_string_no_cch(encoding, &rgce[1..], &cch, &mut formula);
formula.push('\"');
rgce = &rgce[2 + cch..];
}
Expand Down Expand Up @@ -1326,11 +1313,11 @@ fn parse_formula(

/// FormulaValue [MS-XLS 2.5.133]
fn parse_formula_value(r: &[u8]) -> Result<Option<DataType>, XlsError> {
match r {
&[0x00, .., 0xFF, 0xFF] => Ok(None), // String, value should be in next record
&[0x01, _, b, .., 0xFF, 0xFF] => Ok(Some(DataType::Bool(b != 0))),
&[0x02, _, e, .., 0xFF, 0xFF] => parse_err(e).map(Some),
&[e, .., 0xFF, 0xFF] => Err(XlsError::Unrecognized {
match *r {
[0x00, .., 0xFF, 0xFF] => Ok(None), // String, value should be in next record
[0x01, _, b, .., 0xFF, 0xFF] => Ok(Some(DataType::Bool(b != 0))),
[0x02, _, e, .., 0xFF, 0xFF] => parse_err(e).map(Some),
[e, .., 0xFF, 0xFF] => Err(XlsError::Unrecognized {
typ: "error",
val: e,
}),
Expand Down