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
3 changes: 3 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Fixed issue #548 for xls files where the SST record had an incorrect number of
unique strings.


## [0.30.0] - 2025-08-07

Expand Down
13 changes: 9 additions & 4 deletions src/xls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,9 @@ fn parse_dimensions(r: &[u8]) -> Result<Dimensions, XlsError> {
}
}

// Parse the Excel xls Shared String Table (SST). See [MS-XLS] 2.4.265.
//
// https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-xls/b6231b92-d32e-4626-badd-c3310a672bab
fn parse_sst(r: &mut Record<'_>, encoding: &XlsEncoding) -> Result<Vec<String>, XlsError> {
if r.data.len() < 8 {
return Err(XlsError::Len {
Expand All @@ -900,13 +903,15 @@ fn parse_sst(r: &mut Record<'_>, encoding: &XlsEncoding) -> Result<Vec<String>,
found: r.data.len(),
});
}
let len: usize = read_i32(&r.data[4..8]).try_into().unwrap();
let mut sst = Vec::with_capacity(len);
let mut sst = vec![];

// Skip cstTotal and cstUnique headers in SST record.
r.data = &r.data[8..];

for _ in 0..len {
while !r.data.is_empty() || r.continue_record() {
Comment thread
jmcnamara marked this conversation as resolved.
sst.push(read_rich_extended_string(r, encoding)?);
}

Ok(sst)
}

Expand Down Expand Up @@ -958,7 +963,7 @@ fn read_rich_extended_string(
r: &mut Record<'_>,
encoding: &XlsEncoding,
) -> Result<String, XlsError> {
if r.data.is_empty() && !r.continue_record() || r.data.len() < 3 {
if r.data.len() < 3 {
return Err(XlsError::Len {
typ: "rich extended string",
expected: 3,
Expand Down
Binary file added tests/gh548_incorrect_sst_unique_count.xls
Binary file not shown.
Binary file added tests/sst_continue.xls
Binary file not shown.
31 changes: 31 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,37 @@ fn test_oom_allocation() {
assert_eq!(ws[0].0, "Colsale (Aug".to_string());
}

// Test for issue #548. The SST table in the test file has an incorrect unique
// string count.
#[test]
fn test_incorrect_sst_unique_count() {
// Check for the string that appears last in the SST table: "11th May 2023".
// This appears in cell C10 of each worksheet in the workbook.
let mut xls: Xls<_> = wb("gh548_incorrect_sst_unique_count.xls");
let range = xls.worksheet_range("System Level Data").unwrap();

assert_eq!(
range.get_value((9, 2)).unwrap(),
&String("11th May 2023".into())
);
}

// Test the parsing of an SST table that finishes with a complete, untruncated,
// string at the end of the block, and where the next string is in a CONTINUE
// block. This is related to the previous test for gh548 to ensure that the edge
// condition is met.
#[test]
fn test_sst_continue() {
let mut xls: Xls<_> = wb("sst_continue.xls");
let range = xls.worksheet_range("Sheet1").unwrap();

// Check for the string that appears last in the SST table.
assert_eq!(
range.get_value((135, 0)).unwrap(),
&String("New CONTINUE block".into())
);
}

// Test for issue #419 where the part name is sentence case instead of camel
// case. The test file contains a sub-file called "xl/SharedStrings.xml" (note
// the uppercase S in Shared). This is allowed by "Office Open XML File Formats
Expand Down