From 8da6bc8a514b9f4b9b30714c309b25c30f58091e Mon Sep 17 00:00:00 2001 From: Johan Appelgren Date: Mon, 25 May 2026 17:04:00 +0200 Subject: [PATCH] Allow 0xFEFF as byte order in compound document header (#695) Some XLS files generated by propreports have 0xFEFF (bytes FF FE) at the byte order field instead of the expected 0xFFFE (bytes FE FF). Excel and Google Sheets open these files without issue. Since the compound file binary format specifies little-endian byte order unconditionally, the byte order field is informational and safe to be lenient about. Accept 0xFEFF alongside the already-tolerated 0xFFFF. --- .../ExcelBinaryReaderTest.cs | 18 ++++++++++++++++++ .../Core/CompoundFormat/CompoundDocument.cs | 2 +- .../Issue695_InvalidByteOrderFEFF.xls | Bin 0 -> 26112 bytes 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 src/TestData/Issue695_InvalidByteOrderFEFF.xls diff --git a/src/ExcelDataReader.Tests/ExcelBinaryReaderTest.cs b/src/ExcelDataReader.Tests/ExcelBinaryReaderTest.cs index 30ecb25f..376203df 100644 --- a/src/ExcelDataReader.Tests/ExcelBinaryReaderTest.cs +++ b/src/ExcelDataReader.Tests/ExcelBinaryReaderTest.cs @@ -356,6 +356,24 @@ public void AllowFfffAsByteOrder() Assert.That(tableCount, Is.EqualTo(454)); } + [Test] + public void AllowFeffAsByteOrder() + { + using var excelReader = ExcelReaderFactory.CreateBinaryReader(Configuration.GetTestWorkbook("Issue695_InvalidByteOrderFEFF.xls")); + int tableCount = 0; + do + { + while (excelReader.Read()) + { + } + + tableCount++; + } + while (excelReader.NextResult()); + + Assert.That(tableCount, Is.GreaterThan(0)); + } + [Test] public void HandleRowBlocksWithOutOfOrderCells() { diff --git a/src/ExcelDataReader/Core/CompoundFormat/CompoundDocument.cs b/src/ExcelDataReader/Core/CompoundFormat/CompoundDocument.cs index de79cf5c..4f4a3102 100644 --- a/src/ExcelDataReader/Core/CompoundFormat/CompoundDocument.cs +++ b/src/ExcelDataReader/Core/CompoundFormat/CompoundDocument.cs @@ -13,7 +13,7 @@ public CompoundDocument(Stream stream) if (!Header.IsSignatureValid) throw new HeaderException(Errors.ErrorHeaderSignature); - if (Header.ByteOrder != 0xFFFE && Header.ByteOrder != 0xFFFF) // Some broken xls files uses 0xFFFF + if (Header.ByteOrder != 0xFFFE && Header.ByteOrder != 0xFFFF && Header.ByteOrder != 0xFEFF) // Some broken xls files use 0xFFFF or 0xFEFF throw new HeaderException(Errors.ErrorHeaderOrder); var difSectorChain = ReadDifSectorChain(reader); diff --git a/src/TestData/Issue695_InvalidByteOrderFEFF.xls b/src/TestData/Issue695_InvalidByteOrderFEFF.xls new file mode 100644 index 0000000000000000000000000000000000000000..980a49f886cddfa1c2beed0c41a971b8eedd951a GIT binary patch literal 26112 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 AIRF3v literal 0 HcmV?d00001