The writer numbers sheetIds from 1 in sheet order, so a rewritten workbook
changes the id of any sheet that is not part of a gapless series from 1.
Anything that recognises a sheet by its id (parts carried through as they
are, external tools) loses it. The model keeps the sheetId it read
(Sheet::file_id, PreservedSheet::sheet_id, not serialised to JSON) and the
writer writes it back; a new sheet, or a copy with a taken id, gets the first
free one.
Chart sheets (a sheet that holds one chart; Move Chart > New sheet, F11) were
skipped on open, and their chart sheet, drawing, chart, style and colour parts
were dropped with them because the pass-through treats those kinds as content
GridCraft rewrites. Saving a workbook lost every chart sheet.
They are now kept as they were: the <sheet> entry (name, visibility and its
place among the worksheets), the chartsheet part and everything behind it,
byte for byte, written back in place. The workbook's other sheet positions
(active tab, print areas, scoped names) are computed with the chart sheets
counted. A chart sheet is left out on save when the chart is no longer
valid for the workbook: a sheet it plots was deleted or renamed, or a
worksheet took its name.
Excel stores the path of a linked workbook relative to the file that uses it, and rewrites it when the file is saved into another folder. The path was kept as text, so after Save As it named a file next to the new copy: a missing link, or another workbook with the same name. Relative externalLinkPath targets are now resolved against the folder the workbook was read from and written relative to the folder it is saved into (absolute when there is no relative path, on another drive).
Excel uses the cached cell values of a saved file only when workbook.xml has both <fileVersion> and the calcFeatures extension; without them it recalculates everything on open, and lookups into closed workbooks come back as #CALC!. Both are now read into the workbook's kept content and written back in schema order: fileVersion first, the calcFeatures ext in <extLst> last. A workbook that had neither gets neither.
Content types (and extensions) of kept parts come from the input file and
were written into [Content_Types].xml unescaped, so a quote or angle bracket
injected XML; they are now attribute-escaped. Each sheet re-read and kept
its VML drawing (up to 16 MB) outside MAX_KEPT_TOTAL, so many sheets sharing
one highly compressed drawing amplified memory; the drawing is now read
within and charged to the remaining kept-bytes allowance.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pass-through of package content GridCraft does not model: on read the raw
parts are kept with their content types and relationship graph per owner
(package root, workbook, sheet); on write they get fresh part names where
needed and new relationship ids, and the r:ids in kept XML are rewritten.
Kept: custom document properties, ribbon customisation, add-in task panes,
custom XML, links to external workbooks with <externalReferences> (never
followed), connections, sheet query tables, printer settings with the
<pageSetup r:id> (#324), form and ActiveX controls, OLE objects and sheet
backgrounds with their VML shapes (merged with GridCraft's note shapes).
Content whose graph reaches parts GridCraft rewrites is dropped with a
warning; sheet content goes with its sheet and is not copied by Copy Sheet.
Fixes#324
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>