Method: Spreadsheet::Excel::Writer::Workbook#write_changes

Defined in:
lib/spreadsheet/excel/writer/workbook.rb

#write_changes(workbook, io) ⇒ Object

Copy unchanged data verbatim, adjust offsets and write new records for changed data.



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/spreadsheet/excel/writer/workbook.rb', line 160

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