- worker :: DecompTable -> [DomainLabel] -> Get (DomainName, DecompTable)
- worker dt soFar
- = do (l, dt') <- getDomainLabel dt
- case BS.null l of
- True -> return (labelsToName (reverse (l : soFar)), dt')
- False -> worker dt' (l : soFar)
-
-getDomainLabel :: DecompTable -> Get (DomainLabel, DecompTable)
-getDomainLabel dt
- = do header <- getByteString 1
- let Right h
- = runBitGet header $
- do a <- getBit
- b <- getBit
- n <- liftM fromIntegral (getAsWord8 6)
- case (a, b) of
- ( True, True) -> return $ Offset n
- (False, False) -> return $ Length n
- _ -> fail "Illegal label header"
- case h of
- Offset n
- -> do let Just l = IM.lookup n dt
- return (l, dt)
- Length n
- -> do offset <- liftM fromIntegral bytesRead
- label <- getByteString n
- let dt' = IM.insert offset label dt
- return (label, dt')
-
-getCharString :: Get BS.ByteString
-getCharString = do len <- G.getWord8
- getByteString (fromIntegral len)
-
-putCharString :: BS.ByteString -> Put
-putCharString = putDomainLabel
+ worker :: Unpacker DecompTable DomainName
+ worker
+ = do offset <- U.bytesRead
+ hdr <- getLabelHeader
+ case hdr of
+ Offset n
+ -> do dt <- U.getState
+ case IM.lookup n dt of
+ Just name
+ -> return name
+ Nothing
+ -> fail ("Illegal offset of label pointer: " ++ show (n, dt))
+ Length 0
+ -> return rootName
+ Length n
+ -> do label <- U.getByteString n
+ rest <- worker
+ let name = consLabel label rest
+ U.modifyState $ IM.insert offset name
+ return name
+
+ getLabelHeader :: Unpacker s LabelHeader
+ getLabelHeader
+ = do header <- U.lookAhead $ U.getByteString 1
+ let Right h
+ = runBitGet header $
+ do a <- getBit
+ b <- getBit
+ n <- liftM fromIntegral (getAsWord8 6)
+ case (a, b) of
+ ( True, True) -> return $ Offset n
+ (False, False) -> return $ Length n
+ _ -> fail "Illegal label header"
+ case h of
+ Offset _
+ -> do header' <- U.getByteString 2 -- Pointers have 2 octets.
+ let Right h'
+ = runBitGet header' $
+ do BG.skip 2
+ n <- liftM fromIntegral (getAsWord16 14)
+ return $ Offset n
+ return h'
+ len@(Length _)
+ -> do U.skip 1
+ return len
+
+
+getCharString :: Unpacker s BS.ByteString
+getCharString = do len <- U.getWord8
+ U.getByteString (fromIntegral len)
+
+putCharString :: BS.ByteString -> Packer s ()
+putCharString xs = do P.putWord8 $ fromIntegral $ BS.length xs
+ P.putByteString xs