{-# LANGUAGE CPP, BangPatterns, PatternGuards, DeriveDataTypeable #-}
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}

module Codec.Archive.Tar.Index.StringTable (

    StringTable(..),
    lookup,
    index,
    construct,

    StringTableBuilder,
    empty,
    insert,
    inserts,
    finalise,
    unfinalise,

    serialise,
    serialiseSize,
    deserialiseV1,
    deserialiseV2,

    index'
 ) where

import Data.Typeable (Typeable)

import Prelude   hiding (lookup, id)
import Data.List hiding (lookup, insert)
import Data.Function (on)
import Data.Word (Word32)
import Data.Int  (Int32)
import Data.Bits
import Data.Monoid (Monoid(..))
import Data.Monoid ((<>))
import Control.Exception (assert)

import qualified Data.Array.Unboxed as A
import           Data.Array.Unboxed ((!))
import qualified Data.Map.Strict        as Map
import           Data.Map.Strict (Map)
import qualified Data.ByteString        as BS
import qualified Data.ByteString.Unsafe as BS
import qualified Data.ByteString.Lazy   as LBS
import Data.ByteString.Builder          as BS
import Data.ByteString.Builder.Extra    as BS (byteStringCopy)

-- | An efficient mapping from strings to a dense set of integers.
--
data StringTable id = StringTable
         {-# UNPACK #-} !BS.ByteString           -- all strings concatenated
         {-# UNPACK #-} !(A.UArray Int32 Word32) -- string offset table
         {-# UNPACK #-} !(A.UArray Int32 Int32)  -- string index to id table
         {-# UNPACK #-} !(A.UArray Int32 Int32)  -- string id to index table
  deriving (Int -> StringTable id -> ShowS
forall id. Int -> StringTable id -> ShowS
forall id. [StringTable id] -> ShowS
forall id. StringTable id -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [StringTable id] -> ShowS
$cshowList :: forall id. [StringTable id] -> ShowS
show :: StringTable id -> String
$cshow :: forall id. StringTable id -> String
showsPrec :: Int -> StringTable id -> ShowS
$cshowsPrec :: forall id. Int -> StringTable id -> ShowS
Show, Typeable)

instance (Eq id, Enum id) => Eq (StringTable id) where
  StringTable id
tbl1 == :: StringTable id -> StringTable id -> Bool
== StringTable id
tbl2 = forall id. Enum id => StringTable id -> StringTableBuilder id
unfinalise StringTable id
tbl1 forall a. Eq a => a -> a -> Bool
== forall id. Enum id => StringTable id -> StringTableBuilder id
unfinalise StringTable id
tbl2

-- | Look up a string in the token table. If the string is present, return
-- its corresponding index.
--
lookup :: Enum id => StringTable id -> BS.ByteString -> Maybe id
lookup :: forall id. Enum id => StringTable id -> ByteString -> Maybe id
lookup (StringTable ByteString
bs UArray Int32 Word32
offsets UArray Int32 Int32
ids UArray Int32 Int32
_ixs) ByteString
str =
    forall {a}. Enum a => Int32 -> Int32 -> ByteString -> Maybe a
binarySearch Int32
0 (Int32
topBoundforall a. Num a => a -> a -> a
-Int32
1) ByteString
str
  where
    (Int32
0, Int32
topBound) = forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> (i, i)
A.bounds UArray Int32 Word32
offsets

    binarySearch :: Int32 -> Int32 -> ByteString -> Maybe a
binarySearch !Int32
a !Int32
b !ByteString
key
      | Int32
a forall a. Ord a => a -> a -> Bool
> Int32
b     = forall a. Maybe a
Nothing
      | Bool
otherwise = case forall a. Ord a => a -> a -> Ordering
compare ByteString
key (ByteString -> UArray Int32 Word32 -> Int32 -> ByteString
index' ByteString
bs UArray Int32 Word32
offsets Int32
mid) of
          Ordering
LT -> Int32 -> Int32 -> ByteString -> Maybe a
binarySearch Int32
a (Int32
midforall a. Num a => a -> a -> a
-Int32
1) ByteString
key
          Ordering
EQ -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$! forall a. Enum a => Int -> a
toEnum (forall a b. (Integral a, Num b) => a -> b
fromIntegral (UArray Int32 Int32
ids forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Int32
mid))
          Ordering
GT -> Int32 -> Int32 -> ByteString -> Maybe a
binarySearch (Int32
midforall a. Num a => a -> a -> a
+Int32
1) Int32
b ByteString
key
      where mid :: Int32
mid = (Int32
a forall a. Num a => a -> a -> a
+ Int32
b) forall a. Integral a => a -> a -> a
`div` Int32
2

index' :: BS.ByteString -> A.UArray Int32 Word32 -> Int32 -> BS.ByteString
index' :: ByteString -> UArray Int32 Word32 -> Int32 -> ByteString
index' ByteString
bs UArray Int32 Word32
offsets Int32
i = Int -> ByteString -> ByteString
BS.unsafeTake Int
len forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ByteString -> ByteString
BS.unsafeDrop Int
start forall a b. (a -> b) -> a -> b
$ ByteString
bs
  where
    start, end, len :: Int
    start :: Int
start = forall a b. (Integral a, Num b) => a -> b
fromIntegral (UArray Int32 Word32
offsets forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Int32
i)
    end :: Int
end   = forall a b. (Integral a, Num b) => a -> b
fromIntegral (UArray Int32 Word32
offsets forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! (Int32
iforall a. Num a => a -> a -> a
+Int32
1))
    len :: Int
len   = Int
end forall a. Num a => a -> a -> a
- Int
start


-- | Given the index of a string in the table, return the string.
--
index :: Enum id => StringTable id -> id -> BS.ByteString
index :: forall id. Enum id => StringTable id -> id -> ByteString
index (StringTable ByteString
bs UArray Int32 Word32
offsets UArray Int32 Int32
_ids UArray Int32 Int32
ixs) =
    ByteString -> UArray Int32 Word32 -> Int32 -> ByteString
index' ByteString
bs UArray Int32 Word32
offsets forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UArray Int32 Int32
ixs forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
!) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => a -> Int
fromEnum


-- | Given a list of strings, construct a 'StringTable' mapping those strings
-- to a dense set of integers. Also return the ids for all the strings used
-- in the construction.
--
construct :: Enum id => [BS.ByteString] -> StringTable id
construct :: forall id. Enum id => [ByteString] -> StringTable id
construct = forall id. Enum id => StringTableBuilder id -> StringTable id
finalise forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\StringTableBuilder id
tbl ByteString
s -> forall a b. (a, b) -> a
fst (forall id.
Enum id =>
ByteString -> StringTableBuilder id -> (StringTableBuilder id, id)
insert ByteString
s StringTableBuilder id
tbl)) forall id. StringTableBuilder id
empty


data StringTableBuilder id = StringTableBuilder
                                              !(Map BS.ByteString id)
                               {-# UNPACK #-} !Word32
  deriving (StringTableBuilder id -> StringTableBuilder id -> Bool
forall id.
Eq id =>
StringTableBuilder id -> StringTableBuilder id -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: StringTableBuilder id -> StringTableBuilder id -> Bool
$c/= :: forall id.
Eq id =>
StringTableBuilder id -> StringTableBuilder id -> Bool
== :: StringTableBuilder id -> StringTableBuilder id -> Bool
$c== :: forall id.
Eq id =>
StringTableBuilder id -> StringTableBuilder id -> Bool
Eq, Int -> StringTableBuilder id -> ShowS
forall id. Show id => Int -> StringTableBuilder id -> ShowS
forall id. Show id => [StringTableBuilder id] -> ShowS
forall id. Show id => StringTableBuilder id -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [StringTableBuilder id] -> ShowS
$cshowList :: forall id. Show id => [StringTableBuilder id] -> ShowS
show :: StringTableBuilder id -> String
$cshow :: forall id. Show id => StringTableBuilder id -> String
showsPrec :: Int -> StringTableBuilder id -> ShowS
$cshowsPrec :: forall id. Show id => Int -> StringTableBuilder id -> ShowS
Show, Typeable)

empty :: StringTableBuilder id
empty :: forall id. StringTableBuilder id
empty = forall id. Map ByteString id -> Word32 -> StringTableBuilder id
StringTableBuilder forall k a. Map k a
Map.empty Word32
0

insert :: Enum id => BS.ByteString -> StringTableBuilder id -> (StringTableBuilder id, id)
insert :: forall id.
Enum id =>
ByteString -> StringTableBuilder id -> (StringTableBuilder id, id)
insert ByteString
str builder :: StringTableBuilder id
builder@(StringTableBuilder Map ByteString id
smap Word32
nextid) =
    case forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup ByteString
str Map ByteString id
smap of
      Just id
id -> (StringTableBuilder id
builder, id
id)
      Maybe id
Nothing -> let !id :: id
id   = forall a. Enum a => Int -> a
toEnum (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
nextid)
                     !smap' :: Map ByteString id
smap' = forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert ByteString
str id
id Map ByteString id
smap
                   in (forall id. Map ByteString id -> Word32 -> StringTableBuilder id
StringTableBuilder Map ByteString id
smap' (Word32
nextidforall a. Num a => a -> a -> a
+Word32
1), id
id)

inserts :: Enum id => [BS.ByteString] -> StringTableBuilder id -> (StringTableBuilder id, [id])
inserts :: forall id.
Enum id =>
[ByteString]
-> StringTableBuilder id -> (StringTableBuilder id, [id])
inserts [ByteString]
bss StringTableBuilder id
builder = forall (t :: * -> *) s a b.
Traversable t =>
(s -> a -> (s, b)) -> s -> t a -> (s, t b)
mapAccumL (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall id.
Enum id =>
ByteString -> StringTableBuilder id -> (StringTableBuilder id, id)
insert) StringTableBuilder id
builder [ByteString]
bss

finalise :: Enum id => StringTableBuilder id -> StringTable id
finalise :: forall id. Enum id => StringTableBuilder id -> StringTable id
finalise (StringTableBuilder Map ByteString id
smap Word32
_) =
    (forall id.
ByteString
-> UArray Int32 Word32
-> UArray Int32 Int32
-> UArray Int32 Int32
-> StringTable id
StringTable ByteString
strs UArray Int32 Word32
offsets UArray Int32 Int32
ids UArray Int32 Int32
ixs)
  where
    strs :: ByteString
strs    = [ByteString] -> ByteString
BS.concat (forall k a. Map k a -> [k]
Map.keys Map ByteString id
smap)
    offsets :: UArray Int32 Word32
offsets = forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
(i, i) -> [e] -> a i e
A.listArray (Int32
0, forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall k a. Map k a -> Int
Map.size Map ByteString id
smap))
            forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall b a. (b -> a -> b) -> b -> [a] -> [b]
scanl (\Word32
off ByteString
str -> Word32
off forall a. Num a => a -> a -> a
+ forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
BS.length ByteString
str)) Word32
0
            forall a b. (a -> b) -> a -> b
$ forall k a. Map k a -> [k]
Map.keys Map ByteString id
smap
    ids :: UArray Int32 Int32
ids     = forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
(i, i) -> [e] -> a i e
A.listArray (Int32
0, forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall k a. Map k a -> Int
Map.size Map ByteString id
smap) forall a. Num a => a -> a -> a
- Int32
1)
            forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => a -> Int
fromEnum)
            forall a b. (a -> b) -> a -> b
$ forall k a. Map k a -> [a]
Map.elems Map ByteString id
smap
    ixs :: UArray Int32 Int32
ixs     = forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
(i, i) -> [(i, e)] -> a i e
A.array (forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> (i, i)
A.bounds UArray Int32 Int32
ids) [ (Int32
id,Int32
ix) | (Int32
ix,Int32
id) <- forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> [(i, e)]
A.assocs UArray Int32 Int32
ids ]

unfinalise :: Enum id => StringTable id -> StringTableBuilder id
unfinalise :: forall id. Enum id => StringTable id -> StringTableBuilder id
unfinalise (StringTable ByteString
strs UArray Int32 Word32
offsets UArray Int32 Int32
ids UArray Int32 Int32
_) =
    forall id. Map ByteString id -> Word32 -> StringTableBuilder id
StringTableBuilder Map ByteString id
smap Word32
nextid
  where
    smap :: Map ByteString id
smap   = forall k a. Eq k => [(k, a)] -> Map k a
Map.fromAscList
               [ (ByteString -> UArray Int32 Word32 -> Int32 -> ByteString
index' ByteString
strs UArray Int32 Word32
offsets Int32
ix, forall a. Enum a => Int -> a
toEnum (forall a b. (Integral a, Num b) => a -> b
fromIntegral (UArray Int32 Int32
ids forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> i -> e
! Int32
ix)))
               | Int32
ix <- [Int32
0..Int32
h] ]
    (Int32
0,Int32
h)  = forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> (i, i)
A.bounds UArray Int32 Int32
ids
    nextid :: Word32
nextid = forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int32
hforall a. Num a => a -> a -> a
+Int32
1)


-------------------------
-- (de)serialisation
--

serialise :: StringTable id -> BS.Builder
serialise :: forall id. StringTable id -> Builder
serialise (StringTable ByteString
strs UArray Int32 Word32
offs UArray Int32 Int32
ids UArray Int32 Int32
ixs) =
      let (Int32
_, !Int32
ixEnd) = forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> (i, i)
A.bounds UArray Int32 Word32
offs in

      Word32 -> Builder
BS.word32BE (forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
BS.length ByteString
strs))
   forall a. Semigroup a => a -> a -> a
<> Word32 -> Builder
BS.word32BE (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
ixEnd forall a. Num a => a -> a -> a
+ Word32
1)
   forall a. Semigroup a => a -> a -> a
<> ByteString -> Builder
BS.byteStringCopy ByteString
strs
   forall a. Semigroup a => a -> a -> a
<> forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\Word32
n Builder
r -> Word32 -> Builder
BS.word32BE Word32
n forall a. Semigroup a => a -> a -> a
<> Builder
r) forall a. Monoid a => a
mempty (forall (a :: * -> * -> *) e i. (IArray a e, Ix i) => a i e -> [e]
A.elems UArray Int32 Word32
offs)
   forall a. Semigroup a => a -> a -> a
<> forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\Int32
n Builder
r -> Int32 -> Builder
BS.int32BE  Int32
n forall a. Semigroup a => a -> a -> a
<> Builder
r) forall a. Monoid a => a
mempty (forall (a :: * -> * -> *) e i. (IArray a e, Ix i) => a i e -> [e]
A.elems UArray Int32 Int32
ids)
   forall a. Semigroup a => a -> a -> a
<> forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\Int32
n Builder
r -> Int32 -> Builder
BS.int32BE  Int32
n forall a. Semigroup a => a -> a -> a
<> Builder
r) forall a. Monoid a => a
mempty (forall (a :: * -> * -> *) e i. (IArray a e, Ix i) => a i e -> [e]
A.elems UArray Int32 Int32
ixs)

serialiseSize :: StringTable id -> Int
serialiseSize :: forall id. StringTable id -> Int
serialiseSize (StringTable ByteString
strs UArray Int32 Word32
offs UArray Int32 Int32
_ids UArray Int32 Int32
_ixs) =
    let (Int32
_, !Int32
ixEnd) = forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
a i e -> (i, i)
A.bounds UArray Int32 Word32
offs
     in Int
4 forall a. Num a => a -> a -> a
* Int
2
      forall a. Num a => a -> a -> a
+ ByteString -> Int
BS.length ByteString
strs
      forall a. Num a => a -> a -> a
+ Int
4 forall a. Num a => a -> a -> a
* (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
ixEnd forall a. Num a => a -> a -> a
+ Int
1)
      forall a. Num a => a -> a -> a
+ Int
8 forall a. Num a => a -> a -> a
*  forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
ixEnd

deserialiseV1 :: BS.ByteString -> Maybe (StringTable id, BS.ByteString)
deserialiseV1 :: forall id. ByteString -> Maybe (StringTable id, ByteString)
deserialiseV1 ByteString
bs
  | ByteString -> Int
BS.length ByteString
bs forall a. Ord a => a -> a -> Bool
>= Int
8
  , let lenStrs :: Int
lenStrs = forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int -> Word32
readWord32BE ByteString
bs Int
0)
        lenArr :: Int
lenArr  = forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int -> Word32
readWord32BE ByteString
bs Int
4)
        lenTotal :: Int
lenTotal= Int
8 forall a. Num a => a -> a -> a
+ Int
lenStrs forall a. Num a => a -> a -> a
+ Int
4 forall a. Num a => a -> a -> a
* Int
lenArr
  , ByteString -> Int
BS.length ByteString
bs forall a. Ord a => a -> a -> Bool
>= Int
lenTotal
  , let strs :: ByteString
strs = Int -> ByteString -> ByteString
BS.take Int
lenStrs (Int -> ByteString -> ByteString
BS.drop Int
8 ByteString
bs)
        arr :: UArray Int32 Word32
arr  = forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
(i, i) -> [(i, e)] -> a i e
A.array (Int32
0, forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
lenArr forall a. Num a => a -> a -> a
- Int32
1)
                       [ (Int32
i, ByteString -> Int -> Word32
readWord32BE ByteString
bs Int
off)
                       | (Int32
i, Int
off) <- forall a b. [a] -> [b] -> [(a, b)]
zip [Int32
0 .. forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
lenArr forall a. Num a => a -> a -> a
- Int32
1]
                                         [Int
offArrS,Int
offArrSforall a. Num a => a -> a -> a
+Int
4 .. Int
offArrE]
                       ]
        ids :: UArray Int32 Int32
ids  = forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
(i, i) -> [(i, e)] -> a i e
A.array (Int32
0, forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
lenArr forall a. Num a => a -> a -> a
- Int32
1)
                       [ (Int32
i,Int32
i) | Int32
i <- [Int32
0 .. forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
lenArr forall a. Num a => a -> a -> a
- Int32
1] ]
        ixs :: UArray Int32 Int32
ixs  = UArray Int32 Int32
ids -- two identity mappings
        offArrS :: Int
offArrS = Int
8 forall a. Num a => a -> a -> a
+ Int
lenStrs
        offArrE :: Int
offArrE = Int
offArrS forall a. Num a => a -> a -> a
+ Int
4 forall a. Num a => a -> a -> a
* Int
lenArr forall a. Num a => a -> a -> a
- Int
1
        !stringTable :: StringTable id
stringTable = forall id.
ByteString
-> UArray Int32 Word32
-> UArray Int32 Int32
-> UArray Int32 Int32
-> StringTable id
StringTable ByteString
strs UArray Int32 Word32
arr UArray Int32 Int32
ids UArray Int32 Int32
ixs
        !bs' :: ByteString
bs'         = Int -> ByteString -> ByteString
BS.drop Int
lenTotal ByteString
bs
  = forall a. a -> Maybe a
Just (forall {id}. StringTable id
stringTable, ByteString
bs')

  | Bool
otherwise
  = forall a. Maybe a
Nothing

deserialiseV2 :: BS.ByteString -> Maybe (StringTable id, BS.ByteString)
deserialiseV2 :: forall id. ByteString -> Maybe (StringTable id, ByteString)
deserialiseV2 ByteString
bs
  | ByteString -> Int
BS.length ByteString
bs forall a. Ord a => a -> a -> Bool
>= Int
8
  , let lenStrs :: Int
lenStrs = forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int -> Word32
readWord32BE ByteString
bs Int
0)
        lenArr :: Int
lenArr  = forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int -> Word32
readWord32BE ByteString
bs Int
4)
        lenTotal :: Int
lenTotal= Int
8                   -- the two length prefixes
                forall a. Num a => a -> a -> a
+ Int
lenStrs
                forall a. Num a => a -> a -> a
+ Int
4 forall a. Num a => a -> a -> a
* Int
lenArr
                forall a. Num a => a -> a -> a
+(Int
4 forall a. Num a => a -> a -> a
* (Int
lenArr forall a. Num a => a -> a -> a
- Int
1)) forall a. Num a => a -> a -> a
* Int
2 -- offsets array is 1 longer
  , ByteString -> Int
BS.length ByteString
bs forall a. Ord a => a -> a -> Bool
>= Int
lenTotal
  , let strs :: ByteString
strs = Int -> ByteString -> ByteString
BS.take Int
lenStrs (Int -> ByteString -> ByteString
BS.drop Int
8 ByteString
bs)
        offs :: UArray Int32 Word32
offs = forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
(i, i) -> [e] -> a i e
A.listArray (Int32
0, forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
lenArr forall a. Num a => a -> a -> a
- Int32
1)
                           [ ByteString -> Int -> Word32
readWord32BE ByteString
bs Int
off
                           | Int
off <- Int -> [Int]
offsets Int
offsOff ]
        -- the second two arrays are 1 shorter
        ids :: UArray Int32 Int32
ids  = forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
(i, i) -> [e] -> a i e
A.listArray (Int32
0, forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
lenArr forall a. Num a => a -> a -> a
- Int32
2)
                           [ ByteString -> Int -> Int32
readInt32BE ByteString
bs Int
off
                           | Int
off <- Int -> [Int]
offsets Int
idsOff ]
        ixs :: UArray Int32 Int32
ixs  = forall (a :: * -> * -> *) e i.
(IArray a e, Ix i) =>
(i, i) -> [e] -> a i e
A.listArray (Int32
0, forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
lenArr forall a. Num a => a -> a -> a
- Int32
2)
                           [ ByteString -> Int -> Int32
readInt32BE ByteString
bs Int
off
                           | Int
off <- Int -> [Int]
offsets Int
ixsOff ]
        offsOff :: Int
offsOff = Int
8 forall a. Num a => a -> a -> a
+ Int
lenStrs
        idsOff :: Int
idsOff  = Int
offsOff forall a. Num a => a -> a -> a
+ Int
4 forall a. Num a => a -> a -> a
* Int
lenArr
        ixsOff :: Int
ixsOff  = Int
idsOff  forall a. Num a => a -> a -> a
+ Int
4 forall a. Num a => a -> a -> a
* (Int
lenArrforall a. Num a => a -> a -> a
-Int
1)
        offsets :: Int -> [Int]
offsets Int
from = [Int
from,Int
fromforall a. Num a => a -> a -> a
+Int
4 .. Int
from forall a. Num a => a -> a -> a
+ Int
4 forall a. Num a => a -> a -> a
* (Int
lenArr forall a. Num a => a -> a -> a
- Int
1)]
        !stringTable :: StringTable id
stringTable = forall id.
ByteString
-> UArray Int32 Word32
-> UArray Int32 Int32
-> UArray Int32 Int32
-> StringTable id
StringTable ByteString
strs UArray Int32 Word32
offs UArray Int32 Int32
ids UArray Int32 Int32
ixs
        !bs' :: ByteString
bs'         = Int -> ByteString -> ByteString
BS.drop Int
lenTotal ByteString
bs
  = forall a. a -> Maybe a
Just (forall {id}. StringTable id
stringTable, ByteString
bs')

  | Bool
otherwise
  = forall a. Maybe a
Nothing

readInt32BE :: BS.ByteString -> Int -> Int32
readInt32BE :: ByteString -> Int -> Int32
readInt32BE ByteString
bs Int
i = forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int -> Word32
readWord32BE ByteString
bs Int
i)

readWord32BE :: BS.ByteString -> Int -> Word32
readWord32BE :: ByteString -> Int -> Word32
readWord32BE ByteString
bs Int
i =
    forall a. (?callStack::CallStack) => Bool -> a -> a
assert (Int
i forall a. Ord a => a -> a -> Bool
>= Int
0 Bool -> Bool -> Bool
&& Int
iforall a. Num a => a -> a -> a
+Int
3 forall a. Ord a => a -> a -> Bool
<= ByteString -> Int
BS.length ByteString
bs forall a. Num a => a -> a -> a
- Int
1) forall a b. (a -> b) -> a -> b
$
    forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int -> Word8
BS.unsafeIndex ByteString
bs (Int
i forall a. Num a => a -> a -> a
+ Int
0)) forall a. Bits a => a -> Int -> a
`shiftL` Int
24
  forall a. Num a => a -> a -> a
+ forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int -> Word8
BS.unsafeIndex ByteString
bs (Int
i forall a. Num a => a -> a -> a
+ Int
1)) forall a. Bits a => a -> Int -> a
`shiftL` Int
16
  forall a. Num a => a -> a -> a
+ forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int -> Word8
BS.unsafeIndex ByteString
bs (Int
i forall a. Num a => a -> a -> a
+ Int
2)) forall a. Bits a => a -> Int -> a
`shiftL` Int
8
  forall a. Num a => a -> a -> a
+ forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int -> Word8
BS.unsafeIndex ByteString
bs (Int
i forall a. Num a => a -> a -> a
+ Int
3))