@@ -2,7 +2,7 @@
3module Text.XML.Hexml(
3module Text.XML.Hexml(
4 Document, Node, Attribute(..),
4 Document, Node, Attribute(..),
5− parse, render, rootNode,
5+ documentParse, documentRender, documentNode,
6 nodeName, nodeInner, nodeOuter,
6 nodeName, nodeInner, nodeOuter,
7 nodeAttributes, nodeChildren, nodeContents,
7 nodeAttributes, nodeChildren, nodeContents,
8 nodeAttributeBy, nodeChildrenBy
8 nodeAttributeBy, nodeChildrenBy
@@ -12,11 +12,13 @@ import Control.Monad
12import Data.Int
12import Data.Int
13import Foreign.C
13import Foreign.C
14import Foreign.Ptr
14import Foreign.Ptr
15+import Foreign.Marshal hiding (void)
15import Foreign.ForeignPtr
16import Foreign.ForeignPtr
16import Foreign.Storable
17import Foreign.Storable
17import System.IO.Unsafe
18import System.IO.Unsafe
18import Data.Monoid
19import Data.Monoid
20+import Data.Tuple.Extra
19−import qualified Data.ByteString as BS
21+import qualified Data.ByteString.Char8 as BS
20import qualified Data.ByteString.Unsafe as BS
22import qualified Data.ByteString.Unsafe as BS
21import qualified Data.ByteString.Internal as BS
23import qualified Data.ByteString.Internal as BS
@@ -24,13 +26,20 @@ data CDocument
29+szAttr = 2 * sizeOf (undefined :: Str)
30+szNode = 5 * sizeOf (undefined :: Str)
27−data Str = Str {start :: {-# UNPACK #-} !Int32, length :: {-# UNPACK #-} !Int32}
33+data Str = Str {strStart :: {-# UNPACK #-} !Int32, strLength :: {-# UNPACK #-} !Int32} deriving Show
35+strEnd :: Str -> Int32
36+strEnd Str{..} = strStart + strLength
29instance Storable Str where
38instance Storable Str where
30 sizeOf _ = 8
39 sizeOf _ = 8
31 alignment _ = alignment (0 :: Int64)
40 alignment _ = alignment (0 :: Int64)
32 peek p = Str <$> peekByteOff p 0 <*> peekByteOff p 4
41 peek p = Str <$> peekByteOff p 0 <*> peekByteOff p 4
33− poke p Str{..} = pokeByteOff p 0 start >> pokeByteOff p 4 length
42+ poke p Str{..} = pokeByteOff p 0 strStart >> pokeByteOff p 4 strLength
35foreign import ccall document_parse :: CString -> CInt -> IO (Ptr CDocument)
44foreign import ccall document_parse :: CString -> CInt -> IO (Ptr CDocument)
36foreign import ccall document_free :: Ptr CDocument -> IO ()
45foreign import ccall document_free :: Ptr CDocument -> IO ()
@@ -39,8 +48,8 @@ foreign import ccall document_render :: Ptr CDocument -> CString -> CInt -> IO C
39foreign import ccall document_error :: Ptr CDocument -> IO CString
48foreign import ccall document_error :: Ptr CDocument -> IO CString
40foreign import ccall document_node :: Ptr CDocument -> IO (Ptr CNode)
49foreign import ccall document_node :: Ptr CDocument -> IO (Ptr CNode)
42−foreign import ccall node_children :: Ptr CDocument -> Ptr CNode -> Ptr CInt -> Ptr CNode
51+foreign import ccall node_children :: Ptr CDocument -> Ptr CNode -> Ptr CInt -> IO (Ptr CNode)
43−foreign import ccall node_attributes :: Ptr CDocument -> Ptr CNode -> Ptr CInt -> Ptr CAttr
52+foreign import ccall node_attributes :: Ptr CDocument -> Ptr CNode -> Ptr CInt -> IO (Ptr CAttr)
45foreign import ccall node_firstChildBy :: Ptr CDocument -> Ptr CNode -> CString -> CInt -> IO (Ptr CNode)
54foreign import ccall node_firstChildBy :: Ptr CDocument -> Ptr CNode -> CString -> CInt -> IO (Ptr CNode)
46foreign import ccall node_nextChildBy :: Ptr CDocument -> Ptr CNode -> Ptr CNode -> CString -> CInt -> IO (Ptr CNode)
55foreign import ccall node_nextChildBy :: Ptr CDocument -> Ptr CNode -> Ptr CNode -> CString -> CInt -> IO (Ptr CNode)
@@ -50,10 +59,17 @@ data Document = Document BS.ByteString (ForeignPtr CDocument)
51data Node = Node BS.ByteString (ForeignPtr CDocument) (Ptr CNode)
60data Node = Node BS.ByteString (ForeignPtr CDocument) (Ptr CNode)
53−data Attribute = Attribute BS.ByteString BS.ByteString
62+data Attribute = Attribute BS.ByteString BS.ByteString deriving Show
64+instance Show Document where
65+ show d = "Document " ++ show (BS.unpack $ nodeOuter $ documentNode d)
67+instance Show Node where
68+ show d = "Node " ++ show (BS.unpack $ nodeOuter d)
55−parse :: BS.ByteString -> Either BS.ByteString Document
71+documentParse :: BS.ByteString -> Either BS.ByteString Document
56−parse src = unsafePerformIO $ BS.unsafeUseAsCStringLen (src <> BS.singleton 0) $ \(str, len) -> do
72+documentParse src = unsafePerformIO $ BS.unsafeUseAsCStringLen (src <> BS.singleton '\0') $ \(str, len) -> do
57 doc <- document_parse str (fromIntegral len - 1)
73 doc <- document_parse str (fromIntegral len - 1)
58 err <- document_error doc
74 err <- document_error doc
59 if err /= nullPtr then do
75 if err /= nullPtr then do
@@ -64,40 +80,66 @@ parse src = unsafePerformIO $ BS.unsafeUseAsCStringLen (src <> BS.singleton 0) $
64 doc <- newForeignPtr document_free_funptr doc
80 doc <- newForeignPtr document_free_funptr doc
65 return $ Right $ Document src doc
81 return $ Right $ Document src doc
67−render :: Document -> BS.ByteString
83+documentRender :: Document -> BS.ByteString
68−render (Document _ doc) = unsafePerformIO $ withForeignPtr doc $ \d -> do
84+documentRender (Document _ doc) = unsafePerformIO $ withForeignPtr doc $ \d -> do
69 i <- document_render d nullPtr 0
85 i <- document_render d nullPtr 0
70 BS.create (fromIntegral i) $ \ptr -> void $ document_render d (castPtr ptr) i
86 BS.create (fromIntegral i) $ \ptr -> void $ document_render d (castPtr ptr) i
73−rootNode :: Document -> Node
89+documentNode :: Document -> Node
74−rootNode d@(Document src doc) = unsafePerformIO $ withForeignPtr doc $ \d -> do
90+documentNode d@(Document src doc) = unsafePerformIO $ withForeignPtr doc $ \d -> do
75 Node src doc <$> document_node d
91 Node src doc <$> document_node d
77applyStr :: BS.ByteString -> Str -> BS.ByteString
93applyStr :: BS.ByteString -> Str -> BS.ByteString
78−applyStr bs Str{..} = BS.take (fromIntegral length) $ BS.drop (fromIntegral start) bs
94+applyStr bs Str{..} = BS.take (fromIntegral strLength) $ BS.drop (fromIntegral strStart) bs
96+nodeStr :: Int -> Node -> Str
97+nodeStr i (Node src doc n) = unsafePerformIO $ withForeignPtr doc $ \_ -> peekElemOff (castPtr n) i
80−nodePeek :: Int -> Node -> BS.ByteString
99+nodeBS :: Int -> Node -> BS.ByteString
100+nodeBS i node@(Node src doc n) = applyStr src $ nodeStr i node
102+attrPeek :: BS.ByteString -> ForeignPtr CDocument -> Ptr CAttr -> Attribute
81−nodePeek i (Node src doc n) = unsafePerformIO $ withForeignPtr doc $ \_ -> do
103+attrPeek src doc a = unsafePerformIO $ withForeignPtr doc $ \_ -> do
104+ name <- applyStr src <$> peekElemOff (castPtr a) 0
82− applyStr src <$> peekElemOff (castPtr n) i
105+ val <- applyStr src <$> peekElemOff (castPtr a) 1
106+ return $ Attribute name val
84nodeName :: Node -> BS.ByteString
108nodeName :: Node -> BS.ByteString
85−nodeName = nodePeek 0
109+nodeName = nodeBS 0
87nodeInner :: Node -> BS.ByteString
111nodeInner :: Node -> BS.ByteString
88−nodeInner = nodePeek 1
112+nodeInner = nodeBS 1
90nodeOuter :: Node -> BS.ByteString
114nodeOuter :: Node -> BS.ByteString
91−nodeOuter = nodePeek 2
115+nodeOuter = nodeBS 2
117+nodeContents :: Node -> [Either BS.ByteString Node]
118+nodeContents n@(Node src _ _) = f (strStart inner) outers
120+ f i [] = string i (strEnd inner) ++ []
121+ f i ((x, n):xs) = string i (strStart x) ++ Right n : f (strEnd x) xs
93−nodeContents :: Node -> [Either Node BS.ByteString]
123+ string start end | start == end = []
94−nodeContents = undefined
124+ | otherwise = [Left $ applyStr src $ Str start (end - start)]
126+ outers = map (nodeStr 2 &&& id) $ nodeChildren n
96nodeChildren :: Node -> [Node]
128nodeChildren :: Node -> [Node]
129+nodeChildren (Node src doc n) = unsafePerformIO $ withForeignPtr doc $ \d -> do
130+ alloca $ \count -> do
97−nodeChildren = node_children `seq` undefined
131+ res <- node_children d n count
132+ count <- fromIntegral <$> peek count
134+ return [Node src doc $ plusPtr res $ i*sz | i <- [0..count-1]]
99nodeAttributes :: Node -> [Attribute]
136nodeAttributes :: Node -> [Attribute]
137+nodeAttributes (Node src doc n) = unsafePerformIO $ withForeignPtr doc $ \d -> do
138+ alloca $ \count -> do
100−nodeAttributes = node_attributes `seq` undefined
139+ res <- node_attributes d n count
140+ count <- fromIntegral <$> peek count
142+ return [attrPeek src doc (plusPtr res $ i*sz) | i <- [0..count-1]]
102nodeChildrenBy :: Node -> BS.ByteString -> [Node]
144nodeChildrenBy :: Node -> BS.ByteString -> [Node]
103nodeChildrenBy = node_firstChildBy `seq` node_nextChildBy `seq` undefined
145nodeChildrenBy = node_firstChildBy `seq` node_nextChildBy `seq` undefined