openReader :: String -> IO Reader
openReader path = do
  h <- openFile path ReadMode

  version <- hGet32 h
  when (version /= Data.SSTable.version) $
    error $ printf "mismatched versions (expecting %d, got %d)" 
                   Data.SSTable.version version

  -- Fetch the index.
  numBlocks   <- hGet32 h >>= return . fromIntegral
  indexOffset <- hGet64 h >>= return . fromIntegral
  hSeek h AbsoluteSeek indexOffset

  -- Read the index as an array.
  index <- newArray_ (1, numBlocks) :: IO IOIndex

  copy 1 (numBlocks + 1) h index

  -- We don't want to copy the whole index once more, hence the unsafe
  -- freeze.
  liftM (Reader h) $ unsafeFreeze index

  where
    copy i n h index
      | i == n = return ()
      | otherwise = do
          keyLen   <- hGet32 h
          off      <- hGet64 h
          blockLen <- hGet32 h
          key      <- B.hGet h (fromIntegral keyLen)
          writeArray index i (key, fromIntegral off, fromIntegral blockLen)
          copy (i + 1) n h index
openReader :: String -> IO Reader
openReader path = do
  h <- openFile path ReadMode

  version <- hGet32 h
  when (version /= Data.SSTable.version) $
    error $ printf "mismatched versions (expecting %d, got %d)" 
                   Data.SSTable.version version

  -- Fetch the index.
  numBlocks   <- hGet32 h >>= return . fromIntegral
  indexOffset <- hGet64 h >>= return . fromIntegral
  hSeek h AbsoluteSeek indexOffset

  -- Read the index as an array.
  index <- newArray_ (1, numBlocks) :: IO IOIndex

  copy 1 (numBlocks + 1) h index

  -- We don't want to copy the whole index once more, hence the unsafe
  -- freeze.
  liftM (Reader h) $ unsafeFreeze index

  where
    copy i n h index
      | i == n = return ()
      | otherwise = do
          keyLen   <- hGet32 h
          off      <- hGet64 h
          blockLen <- hGet32 h
          key      <- B.hGet h (fromIntegral keyLen)
          writeArray index i (key, fromIntegral off, fromIntegral blockLen)
          copy (i + 1) n h index
openReader path = do
  h <- openFile path ReadMode

  version <- hGet32 h
  when (version /= Data.SSTable.version) $
    error $ printf "mismatched versions (expecting %d, got %d)" 
                   Data.SSTable.version version

  -- Fetch the index.
  numBlocks   <- hGet32 h >>= return . fromIntegral
  indexOffset <- hGet64 h >>= return . fromIntegral
  hSeek h AbsoluteSeek indexOffset

  -- Read the index as an array.
  index <- newArray_ (1, numBlocks) :: IO IOIndex

  copy 1 (numBlocks + 1) h index

  -- We don't want to copy the whole index once more, hence the unsafe
  -- freeze.
  liftM (Reader h) $ unsafeFreeze index

  where
    copy i n h index
      | i == n = return ()
      | otherwise = do
          keyLen   <- hGet32 h
          off      <- hGet64 h
          blockLen <- hGet32 h
          key      <- B.hGet h (fromIntegral keyLen)
          writeArray index i (key, fromIntegral off, fromIntegral blockLen)
          copy (i + 1) n h index