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
9 changes: 9 additions & 0 deletions lib/spreadsheet/excel/reader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,15 @@ def set_row_address worksheet, work, pos, len
xf = (flags & 0x0fff0000) >> 16
attrs.store :default_format, @workbook.format(xf)
end
# When a ROW record claims no cells (`first_used` == `first_unused`) but
# `set_missing_row_address` already recorded a valid offset from cell
# records found earlier in the stream, preserve the original offset.
# Some XLS writers emit ROW records after cell data with zeroed column
# ranges; without this fix, `read_row` would seek to the wrong position.
if first_used == first_unused && (existing = worksheet.row_addresses[index])
attrs[:offset] = existing[:offset]
attrs[:row_block] = existing[:row_block]
end
# TODO: Row spacing
worksheet.set_row_address index, attrs
end
Expand Down
2 changes: 1 addition & 1 deletion lib/spreadsheet/excel/worksheet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Worksheet < Spreadsheet::Worksheet
include Spreadsheet::Excel::Offset

offset :dimensions
attr_reader :offset, :ole, :links, :guts, :notes
attr_reader :offset, :ole, :links, :guts, :notes, :row_addresses
def initialize opts = {}
@row_addresses = nil
super
Expand Down
Binary file added test/data/test_row_record_empty_range.xls
Binary file not shown.
14 changes: 14 additions & 0 deletions test/integration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1217,6 +1217,20 @@ def test_missing_row_op
assert_not_nil sheet[2, 1]
end

def test_row_record_with_empty_cell_range
# Some XLS writers emit ROW records with `first_used` == `first_unused` (claiming
# no cells) even though cell records (e.g. `LABELSST`) exist for that row
# earlier in the stream. Previously this caused `read_row` to seek to the wrong
# offset, returning an empty row despite valid cell data being present.
path = File.join @data, "test_row_record_empty_range.xls"
book = Spreadsheet.open path
sheet = book.worksheet 0
row0 = sheet.row(0).to_a.compact
assert_operator row0.length, :>, 0, "Row 0 should not be empty"
assert_equal "Name", row0[0]
assert_equal ["Name", "Code", "Description", "Reference", "Date", "Quantity"], row0
end

def test_changes
path = File.join @data, "test_changes.xls"
book = Spreadsheet.open path
Expand Down
Loading