Skip to content

Commit 2894bc3

Browse files
authored
Merge pull request #172 from ruby-docx/fix-zip64-scope-to-save-stream
Scope ZIP64 disabling to save/stream (follow-up to #170)
2 parents 16e42c2 + d628376 commit 2894bc3

2 files changed

Lines changed: 64 additions & 28 deletions

File tree

lib/docx/document.rb

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,6 @@
55
require 'nokogiri'
66
require 'zip'
77

8-
# Disable ZIP64 support to maintain compatibility with the previous default behavior
9-
# (before rubyzip 3.x) and ensure compatibility with all readers. Rubyzip 3.x enables
10-
# ZIP64 by default, but many readers (including pandoc) don't support it for small files.
11-
Zip.write_zip64_support = false
12-
138
module Docx
149
# The Document class wraps around a docx file and provides methods to
1510
# interface with it.
@@ -133,40 +128,44 @@ def to_html
133128
# call-seq:
134129
# save(filepath) => void
135130
def save(path)
136-
update
137-
Zip::OutputStream.open(path) do |out|
138-
zip.each do |entry|
139-
next unless entry.file?
131+
with_zip64_disabled do
132+
update
133+
Zip::OutputStream.open(path) do |out|
134+
zip.each do |entry|
135+
next unless entry.file?
140136

141-
out.put_next_entry(entry.name)
142-
value = @replace[entry.name] || zip.read(entry.name)
137+
out.put_next_entry(entry.name)
138+
value = @replace[entry.name] || zip.read(entry.name)
143139

144-
out.write(value)
145-
end
140+
out.write(value)
141+
end
146142

143+
end
144+
zip.close
147145
end
148-
zip.close
149146
end
150147

151148
# Output entire document as a StringIO object
152149
def stream
153-
update
154-
stream = Zip::OutputStream.write_buffer do |out|
155-
zip.each do |entry|
156-
next unless entry.file?
157-
158-
out.put_next_entry(entry.name)
159-
160-
if @replace[entry.name]
161-
out.write(@replace[entry.name])
162-
else
163-
out.write(zip.read(entry.name))
150+
with_zip64_disabled do
151+
update
152+
stream = Zip::OutputStream.write_buffer do |out|
153+
zip.each do |entry|
154+
next unless entry.file?
155+
156+
out.put_next_entry(entry.name)
157+
158+
if @replace[entry.name]
159+
out.write(@replace[entry.name])
160+
else
161+
out.write(zip.read(entry.name))
162+
end
164163
end
165164
end
166-
end
167165

168-
stream.rewind
169-
stream
166+
stream.rewind
167+
stream
168+
end
170169
end
171170

172171
alias text to_s
@@ -189,6 +188,18 @@ def styles_configuration
189188

190189
private
191190

191+
# rubyzip 3.x enables ZIP64 by default, which breaks readers (e.g. pandoc)
192+
# that don't support it for small files (issue #168). Disable ZIP64 only
193+
# while writing, and restore the previous global value afterwards so we
194+
# don't affect other rubyzip users in the consuming application.
195+
def with_zip64_disabled
196+
previous = Zip.write_zip64_support
197+
Zip.write_zip64_support = false
198+
yield
199+
ensure
200+
Zip.write_zip64_support = previous
201+
end
202+
192203
def load_styles
193204
@styles_xml = @zip.read('word/styles.xml')
194205
@styles = Nokogiri::XML(@styles_xml)

spec/docx/document_spec.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,31 @@
376376

377377
after { File.delete(@new_doc_path) if File.exist?(@new_doc_path) }
378378
end
379+
380+
context 'ZIP64 global configuration' do
381+
before { @doc = Docx::Document.open(@fixtures_path + '/basic.docx') }
382+
383+
around do |example|
384+
previous = Zip.write_zip64_support
385+
example.run
386+
Zip.write_zip64_support = previous
387+
end
388+
389+
it 'does not leak the disabled ZIP64 setting after saving' do
390+
Zip.write_zip64_support = true
391+
@new_doc_path = @fixtures_path + '/new_save.docx'
392+
@doc.save(@new_doc_path)
393+
expect(Zip.write_zip64_support).to eq(true)
394+
end
395+
396+
it 'does not leak the disabled ZIP64 setting after streaming' do
397+
Zip.write_zip64_support = true
398+
@doc.stream
399+
expect(Zip.write_zip64_support).to eq(true)
400+
end
401+
402+
after { File.delete(@new_doc_path) if @new_doc_path && File.exist?(@new_doc_path) }
403+
end
379404
end
380405

381406
describe 'streaming' do

0 commit comments

Comments
 (0)