Class: Xlsxrb::Ooxml::ZipWriter
- Inherits:
-
Object
- Object
- Xlsxrb::Ooxml::ZipWriter
- Defined in:
- lib/xlsxrb/ooxml/zip_writer.rb
Overview
Writes ZIP archives using only stdlib (zlib). Supports streaming: entries are written sequentially, central directory at close.
Class Method Summary collapse
Instance Method Summary collapse
-
#add_binary_entry(path, content) ⇒ Object
Add a file entry with binary content (no encoding conversion).
-
#add_entry(path, content) ⇒ Object
Add a file entry with string content.
- #close ⇒ Object
- #finish_entry ⇒ Object
-
#initialize(io) ⇒ ZipWriter
constructor
A new instance of ZipWriter.
-
#start_entry(path) ⇒ Object
Write a string directly into the current ZIP entry stream.
- #write_data(str) ⇒ Object
Constructor Details
#initialize(io) ⇒ ZipWriter
Returns a new instance of ZipWriter.
25 26 27 28 29 |
# File 'lib/xlsxrb/ooxml/zip_writer.rb', line 25 def initialize(io) @io = io @entries = [] @closed = false end |
Class Method Details
.open(target, &block) ⇒ Object
10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/xlsxrb/ooxml/zip_writer.rb', line 10 def self.open(target, &block) io = target.is_a?(String) ? File.open(target, "wb") : target writer = new(io) if block begin yield writer ensure writer.close io.close if target.is_a?(String) end else writer end end |
Instance Method Details
#add_binary_entry(path, content) ⇒ Object
Add a file entry with binary content (no encoding conversion).
40 41 42 43 44 45 |
# File 'lib/xlsxrb/ooxml/zip_writer.rb', line 40 def add_binary_entry(path, content) raise "ZipWriter is closed" if @closed content_bytes = content.b write_raw_entry(path, content_bytes) end |
#add_entry(path, content) ⇒ Object
Add a file entry with string content.
32 33 34 35 36 37 |
# File 'lib/xlsxrb/ooxml/zip_writer.rb', line 32 def add_entry(path, content) raise "ZipWriter is closed" if @closed content_bytes = content.encode("UTF-8").b write_raw_entry(path, content_bytes) end |
#close ⇒ Object
109 110 111 112 113 114 115 116 117 118 |
# File 'lib/xlsxrb/ooxml/zip_writer.rb', line 109 def close return if @closed finish_entry if @current_entry @closed = true cd_offset = @io.is_a?(StringIO) ? @io.pos : @io.tell cd_size = write_central_directory write_end_of_central_directory(cd_offset, cd_size) end |
#finish_entry ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/xlsxrb/ooxml/zip_writer.rb', line 78 def finish_entry raise "No entry started" unless @current_entry entry = @current_entry @current_entry = nil # Flush remaining deflate data remaining = entry[:deflater].finish entry[:compressed_size] += remaining.bytesize @io.write(remaining) entry[:deflater].close final_crc = entry[:crc] & 0xFFFFFFFF # Patch the local header if seekable current_pos = @io.is_a?(StringIO) ? @io.pos : @io.tell if @io.respond_to?(:seek) @io.seek(entry[:offset]) write_local_header(entry[:path], final_crc, entry[:compressed_size], entry[:uncompressed_size]) @io.seek(current_pos) end @entries << { path: entry[:path], crc32: final_crc, compressed_size: entry[:compressed_size], uncompressed_size: entry[:uncompressed_size], offset: entry[:offset] } end |
#start_entry(path) ⇒ Object
Write a string directly into the current ZIP entry stream. Use start_entry / write_data / finish_entry for true streaming.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/xlsxrb/ooxml/zip_writer.rb', line 49 def start_entry(path) raise "ZipWriter is closed" if @closed @current_entry = { path: path, offset: @io.is_a?(StringIO) ? @io.pos : @io.tell, deflater: Zlib::Deflate.new(Zlib::DEFAULT_COMPRESSION, -Zlib::MAX_WBITS), crc: Zlib.crc32, uncompressed_size: 0, compressed_size: 0 } # Write a placeholder local header (will be patched later if IO supports seek) write_local_header(path, 0, 0, 0) end |
#write_data(str) ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/xlsxrb/ooxml/zip_writer.rb', line 65 def write_data(str) raise "No entry started" unless @current_entry bytes = str.b return if bytes.empty? @current_entry[:crc] = Zlib.crc32(bytes, @current_entry[:crc]) @current_entry[:uncompressed_size] += bytes.bytesize compressed = @current_entry[:deflater].deflate(bytes, Zlib::SYNC_FLUSH) @current_entry[:compressed_size] += compressed.bytesize @io.write(compressed) end |