X-Git-Url: https://git.madduck.net/etc/awesome.git/blobdiff_plain/e5c87b4489b0881b7b9903733478f0d11ac96ab7..414b3f2c8793286885e3b999a3911f3b6def630c:/luatz/tzfile.lua diff --git a/luatz/tzfile.lua b/luatz/tzfile.lua index eed426e..9603cfc 100644 --- a/luatz/tzfile.lua +++ b/luatz/tzfile.lua @@ -1,28 +1,45 @@ local tz_info_mt = require "luatz.tzinfo".tz_info_mt +local tt_info_mt = require "luatz.tzinfo".tt_info_mt -local function read_int32be ( fd ) - local data , err = fd:read ( 4 ) - if data == nil then return nil , err end - local o1 , o2 , o3 , o4 = data:byte ( 1 , 4 ) +local read_int32be, read_int64be - local unsigned = o4 + o3*2^8 + o2*2^16 + o1*2^24 - if unsigned >= 2^31 then - return unsigned - 2^32 - else - return unsigned +if string.unpack then -- Only available in Lua 5.3+ + function read_int32be(fd) + local data, err = fd:read(4) + if data == nil then return nil, err end + return string.unpack(">i4", data) end -end -local function read_int64be ( fd ) - local data , err = fd:read ( 8 ) - if data == nil then return nil , err end - local o1 , o2 , o3 , o4 , o5 , o6 , o7 , o8 = data:byte ( 1 , 8 ) + function read_int64be(fd) + local data, err = fd:read(8) + if data == nil then return nil, err end + return string.unpack(">i8", data) + end +else + function read_int32be(fd) + local data, err = fd:read(4) + if data == nil then return nil, err end + local o1, o2, o3, o4 = data:byte(1, 4) + + local unsigned = o4 + o3*2^8 + o2*2^16 + o1*2^24 + if unsigned >= 2^31 then + return unsigned - 2^32 + else + return unsigned + end + end - local unsigned = o8 + o7*2^8 + o6*2^16 + o5*2^24 + o4*2^32 + o3*2^40 + o2*2^48 + o1*2^56 - if unsigned >= 2^63 then - return unsigned - 2^64 - else - return unsigned + function read_int64be(fd) + local data, err = fd:read(8) + if data == nil then return nil, err end + local o1, o2, o3, o4, o5, o6, o7, o8 = data:byte(1, 8) + + local unsigned = o8 + o7*2^8 + o6*2^16 + o5*2^24 + o4*2^32 + o3*2^40 + o2*2^48 + o1*2^56 + if unsigned >= 2^63 then + return unsigned - 2^64 + else + return unsigned + end end end @@ -39,9 +56,9 @@ end local fifteen_nulls = ("\0"):rep(15) local function read_tz ( fd ) - assert ( fd:read(4) == "TZif" ) + assert ( fd:read(4) == "TZif" , "Invalid TZ file" ) local version = assert ( fd:read(1) ) - if version == "\0" or version == "2" then + if version == "\0" or version == "2" or version == "3" then local MIN_TIME = -2^32+1 assert ( assert ( fd:read(15) ) == fifteen_nulls , "Expected 15 nulls" ) @@ -81,7 +98,7 @@ local function read_tz ( fd ) local abbreviations = assert ( fd:read ( tzh_charcnt ) ) - local leap_seconds = { } + local leap_seconds = { } -- luacheck: ignore 241 for i=1, tzh_leapcnt do leap_seconds [ i ] = { offset = assert ( read_int32be ( fd ) ) ; @@ -93,12 +110,15 @@ local function read_tz ( fd ) local isgmt = assert ( read_flags ( fd , tzh_ttisgmtcnt ) ) - if version == "2" then + local TZ + + if version == "2" or version == "3" then --[[ For version-2-format timezone files, the above header and data is followed by a second header and data, identical in format except that eight bytes are used for each transition time or leap-second time. ]] - assert ( fd:read(5) == "TZif2" ) + assert(fd:read(4) == "TZif") + assert(fd:read(1) == version) assert ( assert ( fd:read(15) ) == fifteen_nulls , "Expected 15 nulls" ) MIN_TIME = -2^64+1 @@ -155,6 +175,23 @@ local function read_tz ( fd ) for use in handling instants after the last transition time stored in the file (with nothing between the newlines if there is no POSIX representation for such instants). ]] + + --[[ + For version-3-format time zone files, the POSIX-TZ-style string may + use two minor extensions to the POSIX TZ format, as described in newtzset (3). + First, the hours part of its transition times may be signed and range from + -167 through 167 instead of the POSIX-required unsigned values + from 0 through 24. Second, DST is in effect all year if it starts + January 1 at 00:00 and ends December 31 at 24:00 plus the difference + between daylight saving and standard time. + ]] + + assert ( assert ( fd:read ( 1 ) ) == "\n" , "Expected newline at end of version 2 header" ) + + TZ = assert ( fd:read ( "*l" ) ) + if #TZ == 0 then + TZ = nil + end end for i=1, tzh_typecnt do @@ -162,6 +199,7 @@ local function read_tz ( fd ) v.abbr = abbreviations:sub ( v.abbrind+1 , v.abbrind+3 ) v.isstd = isstd [ i ] or false v.isgmt = isgmt [ i ] or false + setmetatable ( v , tt_info_mt ) end --[[ @@ -180,6 +218,7 @@ local function read_tz ( fd ) end local res = { + future = TZ; [0] = { transition_time = MIN_TIME ; info = ttinfos [ first ] ; @@ -198,7 +237,7 @@ local function read_tz ( fd ) end local function read_tzfile ( path ) - local fd = assert ( io.open ( path ) ) + local fd = assert ( io.open ( path , "rb" ) ) local tzinfo = read_tz ( fd ) fd:close ( ) return tzinfo