class Xlsxrb::Ooxml::ZipWriter
Writes ZIP archives using only stdlib (zlib). Supports streaming: entries are written sequentially, central directory at close.
Public Class Methods
(untyped io) → untyped
Source
# File lib/xlsxrb/ooxml/zip_writer.rb, line 27 def initialize(io) @io = io @entries = [] @closed = false @bytes_written = 0 @seekable = determine_seekable end
(untyped target) ?{ (?) → untyped } → untyped
Source
# File lib/xlsxrb/ooxml/zip_writer.rb, line 12 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
Public Instance Methods
(untyped path, untyped content) → untyped
Source
# File lib/xlsxrb/ooxml/zip_writer.rb, line 44 def add_binary_entry(path, content) raise "ZipWriter is closed" if @closed content_bytes = content.b write_raw_entry(path, content_bytes) end
Add a file entry with binary content (no encoding conversion).
(untyped path, untyped content) → untyped
Source
# File lib/xlsxrb/ooxml/zip_writer.rb, line 36 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
Add a file entry with string content.
() → untyped
Source
# File lib/xlsxrb/ooxml/zip_writer.rb, line 116 def close return if @closed finish_entry if @current_entry @closed = true cd_offset = @bytes_written cd_size = write_central_directory write_end_of_central_directory(cd_offset, cd_size) end
() → untyped
Source
# File lib/xlsxrb/ooxml/zip_writer.rb, line 81 def finish_entry raise "No entry started" unless @has_current_entry @has_current_entry = false # Flush remaining deflate data remaining = @entry_deflater.finish @entry_compressed_size += remaining.bytesize write_bytes(remaining) @entry_deflater.close final_crc = @entry_crc & 0xFFFFFFFF if @entry_seekable # Patch the local header if seekable current_pos = @io.is_a?(StringIO) ? @io.pos : @io.tell @io.seek(@entry_offset) write_local_header(@entry_path, final_crc, @entry_compressed_size, @entry_uncompressed_size, gp_flag: 0, count_bytes: false) @io.seek(current_pos) else # Write Data Descriptor (signature 0x08074b50 + crc32 + comp_size + uncomp_size) descriptor = [0x08074B50, final_crc, @entry_compressed_size, @entry_uncompressed_size].pack("VVVV") write_bytes(descriptor) end @entries << { path: @entry_path, crc32: final_crc, compressed_size: @entry_compressed_size, uncompressed_size: @entry_uncompressed_size, offset: @entry_offset, gp_flag: @entry_gp_flag } end
(untyped path) → untyped
Source
# File lib/xlsxrb/ooxml/zip_writer.rb, line 53 def start_entry(path) raise "ZipWriter is closed" if @closed @entry_path = path @entry_offset = @bytes_written @entry_gp_flag = @seekable ? 0 : 0x0008 @entry_deflater = Zlib::Deflate.new(Zlib::DEFAULT_COMPRESSION, -Zlib::MAX_WBITS) @entry_crc = Zlib.crc32 @entry_uncompressed_size = 0 @entry_compressed_size = 0 @entry_seekable = @seekable @has_current_entry = true # Write local header (if unseekable, sizes/crc are 0 and bit 3 is set) write_local_header(path, 0, 0, 0, gp_flag: @entry_gp_flag) end
Write a string directly into the current ZIP entry stream. Use start_entry / write_data / finish_entry for true streaming.
(untyped str) → untyped
Source
# File lib/xlsxrb/ooxml/zip_writer.rb, line 70 def write_data(str) raise "No entry started" unless @has_current_entry return if str.empty? @entry_crc = Zlib.crc32(str, @entry_crc) @entry_uncompressed_size += str.bytesize compressed = @entry_deflater.deflate(str) @entry_compressed_size += compressed.bytesize write_bytes(compressed) end