xlsxrb 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +104 -0
- data/README.md +17 -14
- data/lib/xlsxrb/colors.rb +118 -0
- data/lib/xlsxrb/elements/cell.rb +205 -16
- data/lib/xlsxrb/elements/column.rb +6 -4
- data/lib/xlsxrb/elements/coordinate_access.rb +32 -0
- data/lib/xlsxrb/elements/image.rb +128 -0
- data/lib/xlsxrb/elements/row.rb +206 -9
- data/lib/xlsxrb/elements/styles.rb +157 -0
- data/lib/xlsxrb/elements/types.rb +95 -1
- data/lib/xlsxrb/elements/workbook.rb +121 -4
- data/lib/xlsxrb/elements/worksheet.rb +519 -29
- data/lib/xlsxrb/elements.rb +2 -0
- data/lib/xlsxrb/number_formatter.rb +429 -0
- data/lib/xlsxrb/ooxml/cfb.rb +1 -1
- data/lib/xlsxrb/ooxml/reader/listeners/core_listeners.rb +7 -5
- data/lib/xlsxrb/ooxml/reader/listeners/drawing_listeners.rb +11 -4
- data/lib/xlsxrb/ooxml/reader/listeners/feature_listeners.rb +7 -1
- data/lib/xlsxrb/ooxml/reader.rb +14 -17
- data/lib/xlsxrb/ooxml/shared_strings_parser.rb +7 -1
- data/lib/xlsxrb/ooxml/styles_parser.rb +39 -9
- data/lib/xlsxrb/ooxml/utils.rb +34 -18
- data/lib/xlsxrb/ooxml/workbook_parser.rb +74 -16
- data/lib/xlsxrb/ooxml/workbook_writer.rb +82 -23
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +319 -79
- data/lib/xlsxrb/ooxml/worksheet_writer.rb +263 -66
- data/lib/xlsxrb/ooxml/writer/features_xml.rb +5 -3
- data/lib/xlsxrb/ooxml/writer.rb +14 -0
- data/lib/xlsxrb/ooxml/xml_builder.rb +14 -2
- data/lib/xlsxrb/ooxml/zip_reader.rb +144 -28
- data/lib/xlsxrb/stream_row.rb +243 -16
- data/lib/xlsxrb/stream_sheet.rb +647 -16
- data/lib/xlsxrb/stream_writer.rb +375 -34
- data/lib/xlsxrb/style_builder.rb +308 -22
- data/lib/xlsxrb/utils.rb +211 -0
- data/lib/xlsxrb/version.rb +1 -1
- data/lib/xlsxrb/workbook_builder.rb +72 -11
- data/lib/xlsxrb/worksheet_builder.rb +738 -24
- data/lib/xlsxrb.rb +1073 -83
- data/sig/generated/xlsxrb/colors.rbs +40 -0
- data/sig/generated/xlsxrb/elements/cell.rbs +113 -8
- data/sig/generated/xlsxrb/elements/column.rbs +3 -2
- data/sig/generated/xlsxrb/elements/coordinate_access.rbs +18 -0
- data/sig/generated/xlsxrb/elements/image.rbs +82 -0
- data/sig/generated/xlsxrb/elements/row.rbs +83 -4
- data/sig/generated/xlsxrb/elements/styles.rbs +79 -0
- data/sig/generated/xlsxrb/elements/types.rbs +43 -0
- data/sig/generated/xlsxrb/elements/workbook.rbs +79 -2
- data/sig/generated/xlsxrb/elements/worksheet.rbs +282 -18
- data/sig/generated/xlsxrb/number_formatter.rbs +132 -0
- data/sig/generated/xlsxrb/ooxml/reader.rbs +6 -0
- data/sig/generated/xlsxrb/ooxml/shared_strings_parser.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/styles_parser.rbs +5 -2
- data/sig/generated/xlsxrb/ooxml/utils.rbs +17 -8
- data/sig/generated/xlsxrb/ooxml/workbook_parser.rbs +9 -3
- data/sig/generated/xlsxrb/ooxml/workbook_writer.rbs +1 -1
- data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +28 -6
- data/sig/generated/xlsxrb/ooxml/worksheet_writer.rbs +13 -3
- data/sig/generated/xlsxrb/ooxml/writer.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/xml_builder.rbs +3 -1
- data/sig/generated/xlsxrb/ooxml/zip_reader.rbs +13 -0
- data/sig/generated/xlsxrb/stream_row.rbs +100 -6
- data/sig/generated/xlsxrb/stream_sheet.rbs +358 -14
- data/sig/generated/xlsxrb/stream_writer.rbs +220 -30
- data/sig/generated/xlsxrb/style_builder.rbs +55 -18
- data/sig/generated/xlsxrb/utils.rbs +151 -0
- data/sig/generated/xlsxrb/workbook_builder.rbs +26 -0
- data/sig/generated/xlsxrb/worksheet_builder.rbs +356 -18
- data/sig/generated/xlsxrb.rbs +223 -27
- metadata +11 -1
data/lib/xlsxrb/ooxml/writer.rb
CHANGED
|
@@ -330,6 +330,19 @@ module Xlsxrb
|
|
|
330
330
|
validate_cell_address!(cell_address)
|
|
331
331
|
sheet_name = sheet || @sheet_order.first
|
|
332
332
|
raise ArgumentError, "unknown sheet: #{sheet_name}" unless @hyperlinks.key?(sheet_name)
|
|
333
|
+
|
|
334
|
+
if url.is_a?(Elements::Hyperlink)
|
|
335
|
+
link = {}
|
|
336
|
+
link[:url] = url.url if url.url
|
|
337
|
+
link[:display] = url.display || display if url.display || display
|
|
338
|
+
link[:tooltip] = url.tooltip || tooltip if url.tooltip || tooltip
|
|
339
|
+
link[:location] = url.location || location if url.location || location
|
|
340
|
+
raise ArgumentError, "url or location required" if link[:url].nil? && link[:location].nil?
|
|
341
|
+
|
|
342
|
+
@hyperlinks[sheet_name][cell_address] = link
|
|
343
|
+
return
|
|
344
|
+
end
|
|
345
|
+
|
|
333
346
|
raise ArgumentError, "url or location required" if url.nil? && location.nil?
|
|
334
347
|
|
|
335
348
|
link = {}
|
|
@@ -997,6 +1010,7 @@ module Xlsxrb
|
|
|
997
1010
|
def set_workbook_property(name, value)
|
|
998
1011
|
@workbook_properties[name] = value
|
|
999
1012
|
end
|
|
1013
|
+
alias workbook_property set_workbook_property
|
|
1000
1014
|
|
|
1001
1015
|
# Returns workbook properties hash.
|
|
1002
1016
|
# : () -> untyped
|
|
@@ -118,14 +118,26 @@ module Xlsxrb
|
|
|
118
118
|
str.match?(ESCAPE_RE) ? str.gsub(ESCAPE_RE, ESCAPE_MAP) : str
|
|
119
119
|
end
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
NUM_ENTITY_RE = /&#(?:(\d+)|x([0-9a-fA-F]+));/
|
|
122
|
+
private_constant :NUM_ENTITY_RE
|
|
123
|
+
|
|
124
|
+
# Unescapes predefined and numeric/hex XML entities in a string.
|
|
122
125
|
#
|
|
123
126
|
# @param value [Object]
|
|
124
127
|
# @return [String]
|
|
125
128
|
#: (untyped value) -> String
|
|
126
129
|
def self.unescape(value)
|
|
127
130
|
str = value.to_s
|
|
128
|
-
str.include?("&")
|
|
131
|
+
return str unless str.include?("&")
|
|
132
|
+
|
|
133
|
+
res = str.gsub(UNESCAPE_RE, UNESCAPE_MAP)
|
|
134
|
+
res.gsub(NUM_ENTITY_RE) do |match|
|
|
135
|
+
dec = Regexp.last_match(1)
|
|
136
|
+
codepoint = dec ? Integer(dec) : Integer(Regexp.last_match(2), 16)
|
|
137
|
+
codepoint.chr(Encoding::UTF_8)
|
|
138
|
+
rescue RangeError
|
|
139
|
+
match
|
|
140
|
+
end
|
|
129
141
|
end
|
|
130
142
|
|
|
131
143
|
private
|
|
@@ -49,6 +49,7 @@ module Xlsxrb
|
|
|
49
49
|
@total_uncompressed = 0
|
|
50
50
|
@eof = false
|
|
51
51
|
@closed = false
|
|
52
|
+
@bom_checked = false
|
|
52
53
|
@inflater = @compression_method == 8 ? Zlib::Inflate.new(-Zlib::MAX_WBITS) : nil
|
|
53
54
|
end
|
|
54
55
|
|
|
@@ -56,6 +57,8 @@ module Xlsxrb
|
|
|
56
57
|
def read(length = nil)
|
|
57
58
|
raise IOError, "closed stream" if @closed
|
|
58
59
|
|
|
60
|
+
check_bom_encoding!
|
|
61
|
+
|
|
59
62
|
if length.nil?
|
|
60
63
|
result = @buffer.dup
|
|
61
64
|
@buffer.clear
|
|
@@ -96,6 +99,11 @@ module Xlsxrb
|
|
|
96
99
|
return if @closed
|
|
97
100
|
|
|
98
101
|
@closed = true
|
|
102
|
+
begin
|
|
103
|
+
@inflater&.reset
|
|
104
|
+
rescue StandardError
|
|
105
|
+
nil
|
|
106
|
+
end
|
|
99
107
|
@inflater&.close
|
|
100
108
|
@inflater = nil
|
|
101
109
|
@buffer.clear
|
|
@@ -176,18 +184,48 @@ module Xlsxrb
|
|
|
176
184
|
nil
|
|
177
185
|
end
|
|
178
186
|
end
|
|
187
|
+
|
|
188
|
+
def check_bom_encoding!
|
|
189
|
+
return if @bom_checked
|
|
190
|
+
|
|
191
|
+
@bom_checked = true
|
|
192
|
+
peek = fetch_chunk(DEFAULT_CHUNK_SIZE)
|
|
193
|
+
return unless peek
|
|
194
|
+
|
|
195
|
+
raw_b = peek.b
|
|
196
|
+
if raw_b.start_with?("\xFF\xFE".b)
|
|
197
|
+
rest = +""
|
|
198
|
+
while (chunk = fetch_chunk(DEFAULT_CHUNK_SIZE))
|
|
199
|
+
rest << chunk
|
|
200
|
+
end
|
|
201
|
+
full = (peek + rest).force_encoding(Encoding::UTF_16LE).encode(Encoding::UTF_8).delete_prefix("\uFEFF")
|
|
202
|
+
@buffer = full
|
|
203
|
+
@eof = true
|
|
204
|
+
elsif raw_b.start_with?("\xFE\xFF".b)
|
|
205
|
+
rest = +""
|
|
206
|
+
while (chunk = fetch_chunk(DEFAULT_CHUNK_SIZE))
|
|
207
|
+
rest << chunk
|
|
208
|
+
end
|
|
209
|
+
full = (peek + rest).force_encoding(Encoding::UTF_16BE).encode(Encoding::UTF_8).delete_prefix("\uFEFF")
|
|
210
|
+
@buffer = full
|
|
211
|
+
@eof = true
|
|
212
|
+
elsif raw_b.start_with?("\xEF\xBB\xBF".b)
|
|
213
|
+
@buffer << peek.b.delete_prefix("\xEF\xBB\xBF".b).force_encoding(Encoding::UTF_8)
|
|
214
|
+
else
|
|
215
|
+
@buffer << peek
|
|
216
|
+
end
|
|
217
|
+
end
|
|
179
218
|
end
|
|
180
219
|
|
|
181
220
|
# Opens a ZIP from a file path or IO and yields the reader.
|
|
182
221
|
#: (untyped source, ?max_uncompressed_size: Integer) ?{ (ZipReader) -> untyped } -> (ZipReader | untyped)
|
|
183
222
|
def self.open(source, max_uncompressed_size: MAX_UNCOMPRESSED_SIZE)
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
end
|
|
223
|
+
is_binary = source.is_a?(String) && (source.start_with?(LOCAL_HEADER_SIG) || source.include?("\x00"))
|
|
224
|
+
should_close = source.is_a?(String) && !is_binary && File.file?(source)
|
|
225
|
+
io = if should_close
|
|
226
|
+
File.open(source, "rb")
|
|
227
|
+
elsif source.is_a?(String)
|
|
228
|
+
StringIO.new(source.b)
|
|
191
229
|
else
|
|
192
230
|
source
|
|
193
231
|
end
|
|
@@ -211,6 +249,7 @@ module Xlsxrb
|
|
|
211
249
|
@tempfile = nil
|
|
212
250
|
@io = nil
|
|
213
251
|
@catalog = nil
|
|
252
|
+
@ci_catalog = nil
|
|
214
253
|
@cached_entries = nil
|
|
215
254
|
end
|
|
216
255
|
|
|
@@ -227,11 +266,15 @@ module Xlsxrb
|
|
|
227
266
|
# Returns raw bytes for a single entry, or nil if not found.
|
|
228
267
|
#: (String name) -> String?
|
|
229
268
|
def read_entry(name)
|
|
230
|
-
|
|
269
|
+
norm_name = normalize_entry_name(name)
|
|
270
|
+
cached = @cached_entries[norm_name] if @cached_entries&.key?(norm_name)
|
|
231
271
|
|
|
232
|
-
entry =
|
|
272
|
+
entry = lookup_entry(norm_name)
|
|
233
273
|
return nil unless entry
|
|
234
274
|
|
|
275
|
+
cached ||= @cached_entries[entry.name] if @cached_entries&.key?(entry.name)
|
|
276
|
+
return normalize_text_encoding(cached) if cached
|
|
277
|
+
|
|
235
278
|
io.seek(entry.data_offset, IO::SEEK_SET)
|
|
236
279
|
raw = io.read(entry.compressed_size)
|
|
237
280
|
decompress(raw, entry.method)
|
|
@@ -250,7 +293,7 @@ module Xlsxrb
|
|
|
250
293
|
# Opens an EntryStreamIO for an entry by name.
|
|
251
294
|
#: (String entry_name) -> EntryStreamIO
|
|
252
295
|
def open_entry_io(entry_name)
|
|
253
|
-
entry =
|
|
296
|
+
entry = lookup_entry(entry_name)
|
|
254
297
|
raise ArgumentError, "Entry not found in archive: #{entry_name}" unless entry
|
|
255
298
|
|
|
256
299
|
EntryStreamIO.new(io, entry.data_offset, entry.compressed_size, entry.method, max_uncompressed_size: @max_uncompressed_size)
|
|
@@ -272,7 +315,7 @@ module Xlsxrb
|
|
|
272
315
|
# Returns true if the archive contains the specified entry.
|
|
273
316
|
#: (String name) -> bool
|
|
274
317
|
def entry?(name)
|
|
275
|
-
|
|
318
|
+
!lookup_entry(name).nil?
|
|
276
319
|
end
|
|
277
320
|
|
|
278
321
|
# Returns entry metadata catalog.
|
|
@@ -290,7 +333,7 @@ module Xlsxrb
|
|
|
290
333
|
# Copies the specified entry to a ZipWriter directly without decompression.
|
|
291
334
|
#: (String entry_name, ZipWriter writer, ?target_path: String?) -> void
|
|
292
335
|
def copy_to_writer(entry_name, writer, target_path: nil)
|
|
293
|
-
entry =
|
|
336
|
+
entry = lookup_entry(entry_name)
|
|
294
337
|
raise ArgumentError, "Entry not found in archive: #{entry_name}" unless entry
|
|
295
338
|
|
|
296
339
|
if entry.compressed_size.zero? && entry.uncompressed_size.positive?
|
|
@@ -354,7 +397,7 @@ module Xlsxrb
|
|
|
354
397
|
cd_catalog = parse_catalog_from_central_directory(io)
|
|
355
398
|
return cd_catalog if cd_catalog && !cd_catalog.empty?
|
|
356
399
|
|
|
357
|
-
io.seek(
|
|
400
|
+
io.seek(0, IO::SEEK_SET) if io.respond_to?(:seek)
|
|
358
401
|
parse_catalog_from_local_headers(io)
|
|
359
402
|
end
|
|
360
403
|
|
|
@@ -394,9 +437,13 @@ module Xlsxrb
|
|
|
394
437
|
|
|
395
438
|
_v_made, _v_need, _gp, method, _time, _date, crc, csize, usize, nlen, elen, clen, _dnum, _iattr, _eattr, offset = cd_header.unpack("vvvvvvVVVvvvvvVV")
|
|
396
439
|
entry_name = io.read(nlen).force_encoding("UTF-8")
|
|
397
|
-
io.read(elen
|
|
440
|
+
extra_data = elen.positive? ? io.read(elen) : nil
|
|
441
|
+
io.read(clen) if clen.positive?
|
|
398
442
|
|
|
399
|
-
|
|
443
|
+
usize, csize, offset = parse_zip64_extra(extra_data, usize, csize, offset) if extra_data && (usize == 0xFFFF_FFFF || csize == 0xFFFF_FFFF || offset == 0xFFFF_FFFF)
|
|
444
|
+
|
|
445
|
+
norm_name = normalize_entry_name(entry_name)
|
|
446
|
+
next if norm_name.end_with?("/")
|
|
400
447
|
|
|
401
448
|
current_cd_pos = io.pos
|
|
402
449
|
|
|
@@ -411,8 +458,8 @@ module Xlsxrb
|
|
|
411
458
|
local_elen = local_header[24, 2].unpack1("v")
|
|
412
459
|
data_offset = offset + 30 + local_nlen + local_elen
|
|
413
460
|
|
|
414
|
-
|
|
415
|
-
name:
|
|
461
|
+
entry = Entry.new(
|
|
462
|
+
name: norm_name,
|
|
416
463
|
method: method,
|
|
417
464
|
compressed_size: csize,
|
|
418
465
|
uncompressed_size: usize,
|
|
@@ -420,6 +467,8 @@ module Xlsxrb
|
|
|
420
467
|
local_header_offset: offset,
|
|
421
468
|
data_offset: data_offset
|
|
422
469
|
)
|
|
470
|
+
result[norm_name] = entry
|
|
471
|
+
result[entry_name] = entry if entry_name != norm_name
|
|
423
472
|
|
|
424
473
|
io.seek(current_cd_pos, IO::SEEK_SET)
|
|
425
474
|
end
|
|
@@ -450,19 +499,22 @@ module Xlsxrb
|
|
|
450
499
|
extra_len = header[24, 2].unpack1("v")
|
|
451
500
|
|
|
452
501
|
entry_name = io.read(name_len).force_encoding("UTF-8")
|
|
453
|
-
io.read(extra_len)
|
|
502
|
+
extra_data = extra_len.positive? ? io.read(extra_len) : nil
|
|
503
|
+
uncompressed_size, compressed_size, = parse_zip64_extra(extra_data, uncompressed_size, compressed_size, 0) if extra_data && (uncompressed_size == 0xFFFF_FFFF || compressed_size == 0xFFFF_FFFF)
|
|
454
504
|
data_offset = io.pos
|
|
455
505
|
|
|
456
|
-
|
|
506
|
+
norm_name = normalize_entry_name(entry_name)
|
|
507
|
+
next if norm_name.end_with?("/")
|
|
457
508
|
|
|
458
509
|
has_data_descriptor = gp_flag.anybits?(0x08)
|
|
459
510
|
|
|
460
511
|
if has_data_descriptor && compressed_size.zero?
|
|
461
512
|
entry_data, = find_data_descriptor_stream(io, method)
|
|
462
513
|
@cached_entries ||= {}
|
|
463
|
-
@cached_entries[
|
|
464
|
-
|
|
465
|
-
|
|
514
|
+
@cached_entries[norm_name] = entry_data
|
|
515
|
+
@cached_entries[entry_name] = entry_data if entry_name != norm_name
|
|
516
|
+
entry = Entry.new(
|
|
517
|
+
name: norm_name,
|
|
466
518
|
method: method,
|
|
467
519
|
compressed_size: entry_data.bytesize,
|
|
468
520
|
uncompressed_size: entry_data.bytesize,
|
|
@@ -470,9 +522,11 @@ module Xlsxrb
|
|
|
470
522
|
local_header_offset: header_pos,
|
|
471
523
|
data_offset: data_offset
|
|
472
524
|
)
|
|
525
|
+
result[norm_name] = entry
|
|
526
|
+
result[entry_name] = entry if entry_name != norm_name
|
|
473
527
|
else
|
|
474
|
-
|
|
475
|
-
name:
|
|
528
|
+
entry = Entry.new(
|
|
529
|
+
name: norm_name,
|
|
476
530
|
method: method,
|
|
477
531
|
compressed_size: compressed_size,
|
|
478
532
|
uncompressed_size: uncompressed_size,
|
|
@@ -480,6 +534,8 @@ module Xlsxrb
|
|
|
480
534
|
local_header_offset: header_pos,
|
|
481
535
|
data_offset: data_offset
|
|
482
536
|
)
|
|
537
|
+
result[norm_name] = entry
|
|
538
|
+
result[entry_name] = entry if entry_name != norm_name
|
|
483
539
|
|
|
484
540
|
io.seek(compressed_size, IO::SEEK_CUR) if io.respond_to?(:seek)
|
|
485
541
|
end
|
|
@@ -527,11 +583,15 @@ module Xlsxrb
|
|
|
527
583
|
end
|
|
528
584
|
|
|
529
585
|
def decompress(raw, method)
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
586
|
+
data = if method.zero?
|
|
587
|
+
raw&.dup || ""
|
|
588
|
+
else
|
|
589
|
+
safe_inflate(raw || "", -Zlib::MAX_WBITS)
|
|
590
|
+
end
|
|
591
|
+
normalize_text_encoding(data)
|
|
533
592
|
rescue Zlib::DataError
|
|
534
|
-
safe_inflate(raw || "", -Zlib::MAX_WBITS)
|
|
593
|
+
data = safe_inflate(raw || "", -Zlib::MAX_WBITS)
|
|
594
|
+
normalize_text_encoding(data)
|
|
535
595
|
end
|
|
536
596
|
|
|
537
597
|
def safe_inflate(raw, wbits)
|
|
@@ -561,6 +621,62 @@ module Xlsxrb
|
|
|
561
621
|
|
|
562
622
|
result.force_encoding("UTF-8")
|
|
563
623
|
end
|
|
624
|
+
|
|
625
|
+
def normalize_entry_name(name)
|
|
626
|
+
name.include?("\\") ? name.tr("\\", "/") : name
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
def lookup_entry(name)
|
|
630
|
+
norm_name = normalize_entry_name(name)
|
|
631
|
+
catalog[norm_name] || ci_catalog[norm_name.downcase]
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
def ci_catalog
|
|
635
|
+
@ci_catalog ||= catalog.transform_keys(&:downcase)
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
def normalize_text_encoding(data)
|
|
639
|
+
return data if data.nil? || data.empty?
|
|
640
|
+
|
|
641
|
+
raw_b = data.b
|
|
642
|
+
if raw_b.start_with?("\xFF\xFE".b)
|
|
643
|
+
data.force_encoding(Encoding::UTF_16LE).encode(Encoding::UTF_8).delete_prefix("\uFEFF")
|
|
644
|
+
elsif raw_b.start_with?("\xFE\xFF".b)
|
|
645
|
+
data.force_encoding(Encoding::UTF_16BE).encode(Encoding::UTF_8).delete_prefix("\uFEFF")
|
|
646
|
+
elsif raw_b.start_with?("\xEF\xBB\xBF".b)
|
|
647
|
+
data.b.delete_prefix("\xEF\xBB\xBF".b).force_encoding(Encoding::UTF_8)
|
|
648
|
+
else
|
|
649
|
+
data.force_encoding(Encoding::UTF_8)
|
|
650
|
+
end
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
#: (String extra_data, Integer usize, Integer csize, Integer offset) -> [Integer, Integer, Integer]
|
|
654
|
+
def parse_zip64_extra(extra_data, usize, csize, offset)
|
|
655
|
+
pos = 0
|
|
656
|
+
len = extra_data.bytesize
|
|
657
|
+
while pos + 4 <= len
|
|
658
|
+
header_id, data_size = extra_data.byteslice(pos, 4).unpack("vv")
|
|
659
|
+
pos += 4
|
|
660
|
+
if header_id == 0x0001
|
|
661
|
+
field_data = extra_data.byteslice(pos, data_size)
|
|
662
|
+
if field_data
|
|
663
|
+
fpos = 0
|
|
664
|
+
if usize == 0xFFFF_FFFF && fpos + 8 <= field_data.bytesize
|
|
665
|
+
usize = field_data.byteslice(fpos, 8).unpack1("Q<")
|
|
666
|
+
fpos += 8
|
|
667
|
+
end
|
|
668
|
+
if csize == 0xFFFF_FFFF && fpos + 8 <= field_data.bytesize
|
|
669
|
+
csize = field_data.byteslice(fpos, 8).unpack1("Q<")
|
|
670
|
+
fpos += 8
|
|
671
|
+
end
|
|
672
|
+
offset = field_data.byteslice(fpos, 8).unpack1("Q<") if offset == 0xFFFF_FFFF && fpos + 8 <= field_data.bytesize
|
|
673
|
+
end
|
|
674
|
+
break
|
|
675
|
+
end
|
|
676
|
+
pos += data_size
|
|
677
|
+
end
|
|
678
|
+
[usize, csize, offset]
|
|
679
|
+
end
|
|
564
680
|
end
|
|
565
681
|
end
|
|
566
682
|
end
|