summaryrefslogtreecommitdiff
path: root/src/EscapeXML.hs
blob: 662d2eddd18d2982b45fea50863adc45f998793d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UnliftedFFITypes #-}
module EscapeXML (escapeXML) where

import Data.Array.Byte
import Data.Text.Internal
import Foreign.C.Types
import GHC.Exts
import GHC.IO (IO(IO))
import System.IO.Unsafe (unsafePerformIO)


foreign import ccall unsafe "tirclogv_escapexml_len"
  c_escapexml_len :: ByteArray# -> CSize -> CSize -> IO CSize

foreign import ccall unsafe "tirclogv_escapexml"
  c_escapexml :: MutableByteArray# RealWorld -> ByteArray# -> CSize -> CSize -> IO ()

{-# NOINLINE escapeXML #-}
escapeXML :: Text -> Text
escapeXML (Text (ByteArray src#) off len) = unsafePerformIO $ do
  let offCS = fromIntegral @Int @CSize off
      lenCS = fromIntegral @Int @CSize len

  reslen <- c_escapexml_len src# offCS lenCS
  let !reslenI@(I# reslen#) = fromIntegral @CSize @Int reslen

  MutableByteArray dst# <-
    IO $ \s -> case newByteArray# reslen# s of
                 (# s', mba# #) -> (# s', MutableByteArray mba# #)
  c_escapexml dst# src# offCS lenCS
  ba <- IO $ \s -> case unsafeFreezeByteArray# dst# s of
                     (# s', ba# #) -> (# s', ByteArray ba# #)

  return (Text ba 0 reslenI)