Class: Xlsxrb::Ooxml::ZipGenerator
- Inherits:
-
Object
- Object
- Xlsxrb::Ooxml::ZipGenerator
- Defined in:
- lib/xlsxrb/ooxml/zip_generator.rb,
sig/generated/xlsxrb/ooxml/zip_generator.rbs
Overview
Generates a simple ZIP file using only the standard library.
Instance Method Summary collapse
-
#add_entry(filepath, content) ⇒ Object
Adds an entry to the ZIP archive.
- #calculate_central_dir_size ⇒ Object
- #compress(content) ⇒ Object
- #crc32(content) ⇒ Object
- #dos_datetime(time) ⇒ Object
-
#generate ⇒ Object
Generates the ZIP file.
-
#initialize(filepath) ⇒ ZipGenerator
constructor
A new instance of ZipGenerator.
- #le16(value) ⇒ Object
- #le32(value) ⇒ Object
- #write_central_directory ⇒ Object
- #write_entries ⇒ Object
- #write_file_data(entry) ⇒ Object
- #write_local_header(entry) ⇒ Object
Constructor Details
#initialize(filepath) ⇒ ZipGenerator
Returns a new instance of ZipGenerator.
11 12 13 14 15 |
# File 'lib/xlsxrb/ooxml/zip_generator.rb', line 11 def initialize(filepath) @filepath = filepath @entries = [] @file = nil end |
Instance Method Details
#add_entry(filepath, content) ⇒ Object
Adds an entry to the ZIP archive.
18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/xlsxrb/ooxml/zip_generator.rb', line 18 def add_entry(filepath, content) compressed_data = compress(content) @entries << { path: filepath, content: content, compressed_data: compressed_data, crc32: crc32(content), uncompressed_size: content.bytesize, compressed_size: compressed_data.bytesize, mtime: Time.now } end |
#calculate_central_dir_size ⇒ Object
154 155 156 |
# File 'lib/xlsxrb/ooxml/zip_generator.rb', line 154 def calculate_central_dir_size @entries.sum { |entry| 46 + entry[:path].bytesize } end |
#compress(content) ⇒ Object
127 128 129 130 131 132 133 134 |
# File 'lib/xlsxrb/ooxml/zip_generator.rb', line 127 def compress(content) deflater = Zlib::Deflate.new(Zlib::DEFAULT_COMPRESSION, -Zlib::MAX_WBITS) begin deflater.deflate(content, Zlib::FINISH) ensure deflater.close end end |
#crc32(content) ⇒ Object
136 137 138 |
# File 'lib/xlsxrb/ooxml/zip_generator.rb', line 136 def crc32(content) Zlib.crc32(content) & 0xFFFFFFFF end |
#dos_datetime(time) ⇒ Object
140 141 142 143 144 |
# File 'lib/xlsxrb/ooxml/zip_generator.rb', line 140 def dos_datetime(time) dos_date = ((time.year - 1980) << 9) | (time.month << 5) | time.day dos_time = (time.hour << 11) | (time.min << 5) | (time.sec / 2) le16(dos_time) + le16(dos_date) end |
#generate ⇒ Object
Generates the ZIP file.
32 33 34 35 36 37 38 |
# File 'lib/xlsxrb/ooxml/zip_generator.rb', line 32 def generate File.open(@filepath, "wb") do |f| @file = f write_entries write_central_directory end end |
#le16(value) ⇒ Object
146 147 148 |
# File 'lib/xlsxrb/ooxml/zip_generator.rb', line 146 def le16(value) [value].pack("v").bytes end |
#le32(value) ⇒ Object
150 151 152 |
# File 'lib/xlsxrb/ooxml/zip_generator.rb', line 150 def le32(value) [value].pack("V").bytes end |
#write_central_directory ⇒ 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 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/xlsxrb/ooxml/zip_generator.rb', line 78 def write_central_directory offset = @file.pos cd_offset = 0 @entries.each do |entry| filename = entry[:path] filename_bytes = filename.bytes cd_header = [] cd_header += [0x50, 0x4b, 0x01, 0x02] # Central directory file header signature cd_header += [0x14, 0x03] # Version made by cd_header += [0x14, 0x00] # Version needed to extract cd_header += [0x00, 0x00] # General purpose bit flag cd_header += [0x08, 0x00] # Compression method dos_time = dos_datetime(entry[:mtime]) cd_header += dos_time cd_header += le32(entry[:crc32]) # CRC-32 cd_header += le32(entry[:compressed_size]) # Compressed size cd_header += le32(entry[:uncompressed_size]) # Uncompressed size cd_header += le16(filename_bytes.length) # Filename length cd_header += le16(0) # Extra field length cd_header += le16(0) # File comment length cd_header += le16(0) # Disk number start cd_header += le16(0) # Internal file attributes cd_header += le32(0) # External file attributes cd_header += le32(cd_offset) # Local header offset @file.write(cd_header.pack("C*")) @file.write(filename) # Advance offset past the local header and compressed data for this entry. cd_offset += 30 + filename_bytes.length + entry[:compressed_size] end # End of central directory record end_cd = [] end_cd += [0x50, 0x4b, 0x05, 0x06] # End of central directory signature end_cd += le16(0) # Disk number end_cd += le16(0) # Disk with central directory end_cd += le16(@entries.length) # Number of central directory records on this disk end_cd += le16(@entries.length) # Total number of central directory records end_cd += le32(calculate_central_dir_size) # Size of central directory end_cd += le32(offset) # Offset of central directory end_cd += le16(0) # Comment length @file.write(end_cd.pack("C*")) end |
#write_entries ⇒ Object
42 43 44 45 46 47 |
# File 'lib/xlsxrb/ooxml/zip_generator.rb', line 42 def write_entries @entries.each do |entry| write_local_header(entry) write_file_data(entry) end end |
#write_file_data(entry) ⇒ Object
74 75 76 |
# File 'lib/xlsxrb/ooxml/zip_generator.rb', line 74 def write_file_data(entry) @file.write(entry[:compressed_data]) end |
#write_local_header(entry) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/xlsxrb/ooxml/zip_generator.rb', line 49 def write_local_header(entry) filename = entry[:path] filename_bytes = filename.bytes # Local file header local_header = [] local_header += [0x50, 0x4b, 0x03, 0x04] # Signature local_header += [0x14, 0x00] # Version needed to extract local_header += [0x00, 0x00] # General purpose bit flag local_header += [0x08, 0x00] # Compression method (8 = deflate) # Last mod file time/date dos_time = dos_datetime(entry[:mtime]) local_header += dos_time local_header += le32(entry[:crc32]) # CRC-32 local_header += le32(entry[:compressed_size]) # Compressed size local_header += le32(entry[:uncompressed_size]) # Uncompressed size local_header += le16(filename_bytes.length) # Filename length local_header += le16(0) # Extra field length @file.write(local_header.pack("C*")) @file.write(filename) end |