@@ -74,36 +74,47 @@ olsonToTimeZoneSeries _ = Nothing
7474-- it into a @TimeZoneSeries@ for use together with the types and
7575-- fucntions of "Data.Time". This is the function from this module
7676-- for which you are most likely to have use.
77+--
78+-- If the values in the Olson timezone file exceed the standard size
79+-- limits (see 'defaultLimits'), this function throws an
80+-- exception. For other behavior, use 'getOlson' and
81+-- 'Data.Binary.Get.runGet' directly.
7782getTimeZoneSeriesFromOlsonFile :: FilePath -> IO TimeZoneSeries
7883getTimeZoneSeriesFromOlsonFile fp = getOlsonFromFile fp >>=
7984 maybe (throwOlson fp "no timezone found in OlsonData") return .
8085 olsonToTimeZoneSeries
8186
8287-- | Parse a binary Olson timezone file.
88+--
89+-- If the values in the Olson timezone file exceed the standard size
90+-- limits (see 'defaultLimits'), this function throws an
91+-- exception. For other behavior, use 'getOlson' and
92+-- 'Data.Binary.Get.runGet' directly.
8393getOlsonFromFile :: FilePath -> IO OlsonData
8494getOlsonFromFile fp = do
85− e <- try . fmap (runGet getOlson) $ L.readFile fp
95+ e <- try . fmap (runGet $ getOlson defaultLimits) $ L.readFile fp
8696 either (formatError fp) return e
8797
8898formatError :: FilePath -> ErrorCall -> IO a
8999formatError fp e = throwOlson fp $ show e
90100
91101-- | A binary parser for binary Olson timezone files
92−getOlson :: Get OlsonData
93−getOlson = do
94− (version, part1) <- getOlsonPart True get32bitInteger
102+getOlson :: SizeLimits -> Get OlsonData
103+getOlson limits = do
104+ (version, part1) <- getOlsonPart True limits get32bitInteger
95105 -- There is one part for Version 1 format data, and two parts and a POSIX
96106 -- TZ string for Version 2 format data
97107 case version of
98108 0 -> return part1
99− 50 -> do (_, part2) <- getOlsonPart False get64bitInteger
109+ 50 -> do (_, part2) <- getOlsonPart False limits get64bitInteger
100110 posixTZ <- getPosixTZ
101111 return $ part1 `mappend` part2 `mappend` posixTZ
102112 _ -> verify (const False) "invalid version number" undefined
103113
104114-- Parse the part of an Olson file that contains timezone data
105−getOlsonPart :: Integral a => Bool -> Get a -> Get (Word8, OlsonData)
106−getOlsonPart verifyMagic getTime = do
115+getOlsonPart :: Integral a => Bool -> SizeLimits -> Get a ->
116+ Get (Word8, OlsonData)
117+getOlsonPart verifyMagic limits getTime = do
107118 magic <- fmap (toASCII . B.unpack) $ getByteString 4
108119 when verifyMagic $ verify_ (== "TZif") "missing magic number" magic
109120 version <- getWord8
@@ -111,9 +122,15 @@ getOlsonPart verifyMagic getTime = do
111122 tzh_ttisgmtcnt <- get32bitInt
112123 tzh_ttisstdcnt <- get32bitInt
113124 tzh_leapcnt <- get32bitInt
125+ >>= verify (withinLimit maxLeaps) "too many leap second specifications"
114126 tzh_timecnt <- get32bitInt
127+ >>= verify (withinLimit maxTimes) "too many timezone transitions"
115128 tzh_typecnt <- get32bitInt
129+ >>= verify (withinLimit maxTypes) "too many timezone type specifications"
130+ verify (withinLimit maxTypes) "too many isgmt specifiers" tzh_ttisgmtcnt
131+ verify (withinLimit maxTypes) "too many isstd specifiers" tzh_ttisstdcnt
116132 tzh_charcnt <- get32bitInt
133+ >>= verify (withinLimit maxAbbrChars) "too many tilezone specifiers"
117134 times <- fmap (map toInteger) $ replicateM tzh_timecnt getTime
118135 indexes <- replicateM tzh_timecnt get8bitInt
119136 ttinfos <- replicateM tzh_typecnt getTtInfo
@@ -131,6 +148,7 @@ getOlsonPart verifyMagic getTime = do
131148 Nothing
132149 )
133150 where
151+ withinLimit limit value = maybe True (value <=) $ limit limits
134152 lookupAbbr (TtInfo gmtoff isdst ttype abbrind) =
135153 TtInfo gmtoff isdst ttype . takeWhile (/= '\NUL') . drop abbrind
136154 setTtype ttinfo ttype = ttinfo {tt_ttype = ttype}