diff --git a/lib/zip/extra_field/universal_time.rb b/lib/zip/extra_field/universal_time.rb index 453b539..5c3b1c1 100644 --- a/lib/zip/extra_field/universal_time.rb +++ b/lib/zip/extra_field/universal_time.rb @@ -4,24 +4,51 @@ module Zip HEADER_ID = 'UT' register_map + ATIME_MASK = 0b010 + CTIME_MASK = 0b100 + MTIME_MASK = 0b001 + def initialize(binstr = nil) @ctime = nil @mtime = nil @atime = nil - @flag = nil - binstr && merge(binstr) + @flag = 0 + + merge(binstr) unless binstr.nil? end - attr_accessor :atime, :ctime, :mtime, :flag + attr_reader :atime, :ctime, :mtime, :flag + + def atime=(time) + @flag = time.nil? ? @flag & ~ATIME_MASK : @flag | ATIME_MASK + @atime = time + end + + def ctime=(time) + @flag = time.nil? ? @flag & ~CTIME_MASK : @flag | CTIME_MASK + @ctime = time + end + + def mtime=(time) + @flag = time.nil? ? @flag & ~MTIME_MASK : @flag | MTIME_MASK + @mtime = time + end def merge(binstr) return if binstr.empty? + size, content = initial_parse(binstr) - size || return - @flag, mtime, atime, ctime = content.unpack('CVVV') - mtime && @mtime ||= ::Zip::DOSTime.at(mtime) - atime && @atime ||= ::Zip::DOSTime.at(atime) - ctime && @ctime ||= ::Zip::DOSTime.at(ctime) + return if !size || size <= 0 + + @flag, *times = content.unpack('ClA", 0b001, true, true, false], + ["UT\x05\x00\x02PS>A", 0b010, false, true, true], + ["UT\x05\x00\x04PS>A", 0b100, true, false, true], + ["UT\x09\x00\x03PS>APS>A", 0b011, false, true, false], + ["UT\x09\x00\x05PS>APS>A", 0b101, true, false, false], + ["UT\x09\x00\x06PS>APS>A", 0b110, false, false, true], + ["UT\x13\x00\x07PS>APS>APS>A", 0b111, false, false, false] + ] + + def test_parse + PARSE_TESTS.each do |bin, flags, a, c, m| + ut = ::Zip::ExtraField::UniversalTime.new(bin) + assert_equal(flags, ut.flag) + assert(ut.atime.nil? == a) + assert(ut.ctime.nil? == c) + assert(ut.mtime.nil? == m) + end + end + + def test_parse_size_zero + ut = ::Zip::ExtraField::UniversalTime.new("UT\x00") + assert_equal(0b000, ut.flag) + assert_nil(ut.atime) + assert_nil(ut.ctime) + assert_nil(ut.mtime) + end + + def test_parse_size_nil + ut = ::Zip::ExtraField::UniversalTime.new('UT') + assert_equal(0b000, ut.flag) + assert_nil(ut.atime) + assert_nil(ut.ctime) + assert_nil(ut.mtime) + end + + def test_parse_nil + ut = ::Zip::ExtraField::UniversalTime.new + assert_equal(0b000, ut.flag) + assert_nil(ut.atime) + assert_nil(ut.ctime) + assert_nil(ut.mtime) + end + + def test_set_clear_times + time = ::Zip::DOSTime.now + ut = ::Zip::ExtraField::UniversalTime.new + assert_equal(0b000, ut.flag) + + ut.mtime = time + assert_equal(0b001, ut.flag) + assert_equal(time, ut.mtime) + + ut.ctime = time + assert_equal(0b101, ut.flag) + assert_equal(time, ut.ctime) + + ut.atime = time + assert_equal(0b111, ut.flag) + assert_equal(time, ut.atime) + + ut.ctime = nil + assert_equal(0b011, ut.flag) + assert_nil ut.ctime + + ut.mtime = nil + assert_equal(0b010, ut.flag) + assert_nil ut.mtime + + ut.atime = nil + assert_equal(0b000, ut.flag) + assert_nil ut.atime + end + + def test_pack + time = ::Zip::DOSTime.at('PS>A'.unpack1('l<')) + ut = ::Zip::ExtraField::UniversalTime.new + assert_equal("\x00", ut.pack_for_local) + assert_equal("\x00", ut.pack_for_c_dir) + + ut.mtime = time + assert_equal("\x01PS>A", ut.pack_for_local) + assert_equal("\x01PS>A", ut.pack_for_c_dir) + + ut.atime = time + assert_equal("\x03PS>APS>A", ut.pack_for_local) + assert_equal("\x03PS>A", ut.pack_for_c_dir) + + ut.ctime = time + assert_equal("\x07PS>APS>APS>A", ut.pack_for_local) + assert_equal("\x07PS>A", ut.pack_for_c_dir) + end +end