# File lib/spreadsheet/excel/writer/workbook.rb, line 168
  def write_changes workbook, io
    sanitize_worksheets workbook.worksheets
    collect_formats workbook, :existing_document => true
    reader = workbook.ole
    sheet_data = {}
    sst_status, sst_total, sst_strings = complete_sst_update? workbook
    sst = {}
    sst_strings.each_with_index do |str, idx| sst.store str, idx end
    sheets = worksheets(workbook)
    positions = []
    newsheets = []
    sheets.each do |sheet|
      @sst[sheet] = sst
      pos, len = workbook.offsets[sheet.worksheet]
      if pos
        positions.push pos
        sheet.write_changes reader, pos + len, sst_status
      else
        newsheets.push sheet
        sheet.write_from_scratch
      end
      sheet_data[sheet.worksheet] = sheet.data
    end
    Ole::Storage.open io do |ole|
      ole.file.open 'Workbook', 'w' do |writer|
        reader.seek lastpos = 0
        workbook.offsets.select do |key, pair|
          workbook.changes.include? key
        end.sort_by do |key, (pos, len)|
          pos
        end.each do |key, (pos, len)|
          data = reader.read(pos - lastpos)
          writer.write data
          case key
          when Spreadsheet::Worksheet
            writer.write sheet_data[key]
          when :boundsheets
            ## boundsheets are hard to calculate. The offset below is only
            #  correct if there are no more changes in the workbook globals
            #  string after this.
            oldoffset = positions.min - len
            lastpos = pos + len
            bytechange = 0
            buffer = StringIO.new ''
            if tuple = workbook.offsets[:sst]
              write_sst_changes workbook, buffer, writer.pos,
                                sst_total, sst_strings
              pos, len = tuple
              if offset = workbook.offsets[:extsst]
                len += offset[1].to_i
              end
              bytechange = buffer.size - len
              write_boundsheets workbook, writer, oldoffset + bytechange
              reader.seek lastpos
              writer.write reader.read(pos - lastpos)
              buffer.rewind
              writer.write buffer.read
            elsif sst.empty? || workbook.biff_version < 8
              write_boundsheets workbook, writer, oldoffset + bytechange
            else
              write_sst workbook, buffer, writer.pos
              write_boundsheets workbook, writer, oldoffset + buffer.size
              pos = lastpos
              len = positions.min - lastpos
              if len > OPCODE_SIZE
                reader.seek pos
                writer.write reader.read(len - OPCODE_SIZE)
              end
              buffer.rewind
              writer.write buffer.read
              write_eof workbook, writer
            end
          else
            send "write_#{key}", workbook, writer
          end
          lastpos = [pos + len, reader.size - 1].min
          reader.seek lastpos
        end
        writer.write reader.read
        newsheets.each do |sheet|
          writer.write sheet.data
        end
      end
    end
  end