diff --git a/property-list.cabal b/property-list.cabal
--- a/property-list.cabal
+++ b/property-list.cabal
@@ -1,9 +1,9 @@
 name:                   property-list
-version:                0.0.3
+version:                0.1
 stability:              experimental
 license:                PublicDomain
 
-cabal-version:          >= 1.2
+cabal-version:          >= 1.6
 build-type:             Simple
 
 author:                 James Cook <james.cook@usma.edu>
@@ -14,45 +14,43 @@
 synopsis:               XML property list parser
 description:            Parser, data type and formatter for Apple's XML property list 1.0 format.
 
-flag HaXml_1_13
-  default:              False
-  description:          Compile against HaXml 1.13 rather than the latest.
+tested-with:            GHC == 6.12.3, GHC == 7.0.4
 
+source-repository head
+  type:                 git
+  location:             git://github.com/mokus0/property-list.git
+
 Library
   hs-source-dirs:       src
   ghc-options:          -fwarn-unused-binds -fwarn-unused-imports
   exposed-modules:      Data.PropertyList
                         Data.PropertyList.Algebra
+                        Data.PropertyList.Binary
                         Data.PropertyList.Xml
                         
   other-modules:        Data.PropertyList.Types
+                        Data.PropertyList.Binary.Algebra
+                        Data.PropertyList.Binary.Linearize
+                        Data.PropertyList.Binary.Float
+                        Data.PropertyList.Binary.Get
+                        Data.PropertyList.Binary.Put
+                        Data.PropertyList.Binary.Types
                         Data.PropertyList.PropertyListItem
                         Data.PropertyList.KeyPath
-                        Data.PropertyList.Xml.Parse
-                        Data.PropertyList.Xml.Types
-  build-depends:        base >= 4 && <5,
+                        Data.PropertyList.Xml.Algebra
+  build-depends:        base >= 3 && <5,
+                        base64-bytestring,
                         bytestring,
-                        bytestring-class,
+                        cereal,
                         containers, 
-                        comonad-transformers >= 1.8,
-                        dataenc,
                         free >= 1.8,
-                        mtl,
+                        transformers,
                         old-locale,
-                        pointed >= 1.8,
-                        pretty,
+                        oneOfN,
                         recursion-schemes >= 1.8,
                         syb,
                         template-haskell,
+                        text,
                         time,
-                        th-fold,
-                        void
-
-  if flag(HaXml_1_13)
-    other-modules:      Data.PropertyList.Xml.Dtd_1_13
-    cpp-options:        -DHaXml_1_13
-    build-depends:      HaXml >= 1.13 && <1.14
-                        
-  else
-    other-modules:      Data.PropertyList.Xml.Dtd
-    build-depends:      HaXml >= 1.19
+                        vector,
+                        xml >= 1.3.9
diff --git a/src/Data/PropertyList.hs b/src/Data/PropertyList.hs
--- a/src/Data/PropertyList.hs
+++ b/src/Data/PropertyList.hs
@@ -14,14 +14,13 @@
       -- into their overall shape but not all elements have been parsed into
       -- their final format.
       -- 
-      -- The 'UnparsedPlistItem' type is the type most often used with
-      -- 'PartialPropertyList', and that is really its only purpose - to
-      -- represent unparseable items from an XML plist during intermediate
-      -- stages of translation.
+      -- The 'UnparsedXmlPlistItem' and 'UnparsedBPListRecord' types are used
+      -- with 'PartialPropertyList', and that is really their only purpose - to
+      -- represent unparseable items during intermediate stages of translation.
       PropertyList
     , PartialPropertyList
-    , PropertyListS(..)
-    , UnparsedPlistItem(..)
+    , UnparsedBPListRecord(..)
+    , UnparsedXmlPlistItem(..)
       
     -- * Constructors and destructors for property lists
     -- |The \"pl*\" operations construct 'PropertyList's, 'PartialPropertyList's, 
@@ -57,12 +56,16 @@
     , InitialPList, TerminalPList
 
     -- * Parsing and formatting property lists using any supported format
-    , readPropertyList
-    , showPropertyList
-    
     , readPropertyListFromFile
     , writePropertyListToFile
     
+    -- * Parsing and formatting property lists using the Binary format
+    , readBinaryPropertyList
+    , encodeBinaryPropertyList
+    
+    , readBinaryPropertyListFromFile
+    , writeBinaryPropertyListToFile
+    
     -- * Parsing and formatting property lists using the XML format
     , readXmlPropertyList
     , showXmlPropertyList
@@ -126,28 +129,37 @@
     , module Data.PropertyList.KeyPath
     ) where
 
+import Control.Exception (try, SomeException(..))
+
 import Data.PropertyList.Algebra
+import Data.PropertyList.Binary
 import Data.PropertyList.Types
 import Data.PropertyList.Xml
 
 import Data.PropertyList.PropertyListItem
 import Data.PropertyList.KeyPath
 
--- | Read a property list from a 'String', trying all supported property list formats.
--- Presently, only the \"XML1\" format is supported.  See also 'readXmlPropertyList'.
-readPropertyList :: String -> Either String PropertyList
-readPropertyList = readXmlPropertyList
-
--- | Write a property list to a 'String', using a \"preferred\" property list format.
--- Presently, that is the \"XML1\" format.  See also 'showXmlPropertyList'.
-showPropertyList :: PropertyList -> String
-showPropertyList = showXmlPropertyList
-
 -- | Read a property list from a file, trying all supported property list formats.
--- Presently, only the \"XML1\" format is supported.  See also
--- 'readXmlPropertyListFromFile'.
+-- Presently, the \"XML1\" and \"bplist00\" formats are supported.  See also
+-- 'readXmlPropertyListFromFile' and 'readBinaryPropertyListFromFile'.
 readPropertyListFromFile :: FilePath -> IO PropertyList
-readPropertyListFromFile = readXmlPropertyListFromFile
+readPropertyListFromFile file = do
+    partial <- readPartial file
+    case partial of
+        Left  xml -> completePropertyListByM barf xml
+        Right bin -> completePropertyListByM barf bin
+    where
+        readPartial :: FilePath -> IO (Either
+            (PartialPropertyList UnparsedXmlPlistItem)
+            (PartialPropertyList UnparsedBPListRecord))
+        readPartial file = do
+            mbPartial <- try (readBinaryPartialPropertyListFromFile file)
+            case mbPartial of
+                Left SomeException{} -> fmap Left (readXmlPartialPropertyListFromFile file)
+                Right bin            -> return (Right bin)
+        
+        barf :: Show a => a -> IO PropertyList
+        barf unparsed = fail ("Unparseable item found: " ++ show unparsed)
 
 -- | Write a property list to a file, using a \"preferred\" property list format.
 -- Presently, that is the \"XML1\" format.  See also 'writeXmlPropertyListToFile'.
diff --git a/src/Data/PropertyList/Algebra.hs b/src/Data/PropertyList/Algebra.hs
--- a/src/Data/PropertyList/Algebra.hs
+++ b/src/Data/PropertyList/Algebra.hs
@@ -1,8 +1,6 @@
-{-# LANGUAGE 
-    MultiParamTypeClasses, FunctionalDependencies,
-    TemplateHaskell,
-    FlexibleContexts
-  #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE FlexibleContexts #-}
 
 -- |The internal \"algebraic\" interface for working with property-list-like
 -- things.  The classes defined here are the basis for a very general system
@@ -31,16 +29,13 @@
 module Data.PropertyList.Algebra where
 
 import Control.Applicative
-import Control.Monad.Identity
+import Data.Functor.Identity
+import Data.ByteString as B hiding (map)
 import Data.Foldable (Foldable(foldMap))
-import Data.Traversable (Traversable(..))
-import Data.Monoid
-
-import Language.Haskell.TH.Fold (fold)
-
 import qualified Data.Map as M
-import Data.ByteString as B hiding (map)
+import Data.Monoid
 import Data.Time
+import Data.Traversable (Traversable(..))
 
 -- * The signature type ('PropertyListS')
 
@@ -92,7 +87,16 @@
                   -> (String -> t)
                   -> (Bool -> t) 
                   -> PropertyListS a -> t
-foldPropertyListS = $(fold ''PropertyListS)
+foldPropertyListS plArray plData plDate plDict plReal plInt plString plBool pl =
+    case pl of
+        PLArray   x -> plArray   x
+        PLData    x -> plData    x
+        PLDate    x -> plDate    x
+        PLDict    x -> plDict    x
+        PLReal    x -> plReal    x
+        PLInt     x -> plInt     x
+        PLString  x -> plString  x
+        PLBool    x -> plBool    x
 
 instance Functor PropertyListS where
     fmap f = foldPropertyListS (PLArray . fmap f) PLData PLDate (PLDict . fmap f) PLReal PLInt PLString PLBool
diff --git a/src/Data/PropertyList/Binary.hs b/src/Data/PropertyList/Binary.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/PropertyList/Binary.hs
@@ -0,0 +1,54 @@
+module Data.PropertyList.Binary
+    ( BPListHeader(..), BPListTrailer(..)
+    , BPListRecord(..), BPListRecords(..)
+    , readBPListRecords, putBPList
+    
+    , Abs, Rel
+    , linearize, delinearize, absolutize, intern
+    
+    , UnparsedBPListRecord(..)
+    , readBinaryPartialPropertyList
+    , readBinaryPartialPropertyListFromFile
+    
+    , readBinaryPropertyList
+    , readBinaryPropertyListFromFile
+    
+    , encodeBinaryPropertyList
+    , writeBinaryPropertyListToFile
+    ) where
+
+import Control.Applicative
+import Data.Serialize.Put
+import qualified Data.ByteString.Lazy as BL
+import Data.PropertyList.Types
+import Data.PropertyList.Binary.Algebra ({- instances -})
+import Data.PropertyList.Binary.Linearize
+import Data.PropertyList.Binary.Get
+import Data.PropertyList.Binary.Put
+import Data.PropertyList.Binary.Types
+
+readBinaryPartialPropertyList :: BL.ByteString -> Either String (PartialPropertyList UnparsedBPListRecord)
+readBinaryPartialPropertyList bs = do
+    delinearize <$> readBPListRecords bs
+
+readBinaryPropertyList :: BL.ByteString -> Either String PropertyList
+readBinaryPropertyList bs = do
+    readBinaryPartialPropertyList bs >>= completePropertyListByM barf
+    where barf unparsed = Left ("Unparseable item found: " ++ show unparsed) :: Either String PropertyList
+
+readBinaryPropertyListFromFile :: FilePath -> IO PropertyList
+readBinaryPropertyListFromFile path = do
+    contents <- BL.readFile path
+    either fail return (readBinaryPropertyList contents)
+
+readBinaryPartialPropertyListFromFile :: FilePath -> IO (PartialPropertyList UnparsedBPListRecord)
+readBinaryPartialPropertyListFromFile file = do
+    bs <- BL.readFile file
+    either fail return (readBinaryPartialPropertyList bs)
+
+encodeBinaryPropertyList :: PropertyList -> BL.ByteString
+encodeBinaryPropertyList = runPutLazy . putBPList . linearize
+
+writeBinaryPropertyListToFile :: FilePath -> PropertyList -> IO ()
+writeBinaryPropertyListToFile path = 
+    BL.writeFile path . encodeBinaryPropertyList
diff --git a/src/Data/PropertyList/Binary/Algebra.hs b/src/Data/PropertyList/Binary/Algebra.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/PropertyList/Binary/Algebra.hs
@@ -0,0 +1,71 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+module Data.PropertyList.Binary.Algebra where
+
+import Data.Monoid
+import Data.Functor.Identity
+import Data.PropertyList.Algebra
+import Data.PropertyList.Binary.Types
+import Data.Sequence as S ((<|), (><))
+import qualified Data.Sequence as S
+import qualified Data.Map as M
+
+instance PListAlgebra Identity (BPListRecords Rel) where
+    plistAlgebra = BPListRecords 0 . flatten . runIdentity
+        where
+            indexFrom n [] = []
+            indexFrom n (BPListRecords root recs : rest)
+                = n + fromIntegral root : indexFrom (n + fromIntegral (S.length recs)) rest
+            
+            flatten (PLArray  xss)
+                =  BPLArray (indexFrom 1 xss)
+                <| mconcat (map records xss)
+            flatten (PLDict   kvs)
+                =  BPLDict [1..nks] (indexFrom (nks+1) vss)
+                <| S.fromList (map BPLString ks)
+                >< mconcat (map records vss)
+                where
+                    nks = fromIntegral (M.size kvs)
+                    ks  = M.keys  kvs
+                    vss = M.elems kvs
+            flatten (PLData  bs) = S.singleton (BPLData  bs)
+            flatten (PLDate   t) = S.singleton (BPLDate   t)
+            flatten (PLReal   r) = S.singleton (BPLReal   r)
+            flatten (PLInt    i) = S.singleton (BPLInt    i)
+            flatten (PLString s) = S.singleton (BPLString s)
+            flatten (PLBool   b) = S.singleton (BPLBool   b)
+
+instance PListCoalgebra (Either UnparsedBPListRecord) (BPListRecords Abs) where
+    plistCoalgebra (BPListRecords root recs) = fmap (fmap (flip BPListRecords recs)) (unpackRec root)
+        where
+            unpackRec i
+                | fromIntegral i >= S.length recs
+                    = Left (MissingObjectRef i)
+                | otherwise
+                    = case S.index recs (fromIntegral i) of
+                        BPLNull         -> Left UnparsedNull
+                        BPLFill         -> Left UnparsedFill
+                        BPLSet s        -> Left (UnparsedSet s)
+                        BPLUID s        -> Left (UnparsedUID s)
+                        BPLArray   xs   -> Right (PLArray xs)
+                        BPLData     x   -> Right (PLData x)
+                        BPLDate     x   -> Right (PLDate x)
+                        BPLDict ks vs   -> do
+                            ks <- mapM (unpackStringOr (UnparsedDict ks vs)) ks
+                            return (PLDict (M.fromList (zip ks vs)))
+                        BPLReal     x   -> Right (PLReal x)
+                        BPLInt      x   -> Right (PLInt x)
+                        BPLString   x   -> Right (PLString x)
+                        BPLBool     x   -> Right (PLBool x)
+            
+            unpackStringOr barf k = do
+                key <- unpackRec k
+                case key of
+                    PLString s  -> Right s
+                    _           -> Left barf
+
+-- To support smart-deconstructors:
+instance PListCoalgebra Maybe (BPListRecords Abs) where
+    plistCoalgebra 
+        = either (const Nothing :: UnparsedBPListRecord -> Maybe t) Just
+        . plistCoalgebra
diff --git a/src/Data/PropertyList/Binary/Float.hs b/src/Data/PropertyList/Binary/Float.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/PropertyList/Binary/Float.hs
@@ -0,0 +1,86 @@
+{-# LANGUAGE TemplateHaskell #-}
+module Data.PropertyList.Binary.Float
+    ( doubleToWord64
+    , word64ToDouble
+    
+    , floatToWord32
+    , word32ToFloat
+    
+    , doubleToEquivalentFloat
+    ) where
+
+import Foreign
+import GHC.Float
+
+-- TODO: create a library or extend an existing one to include a module Data.Float.IEEE
+-- which exports types Float32, Float64, etc., with proper IEEE-safe conversions
+-- and C union-style conversions to corresponding Word types...
+
+$( do
+    let assertFloatProp :: (Monad m, Eq a) => String -> (Float -> a) -> a -> m ()
+        assertFloatProp desc p x
+            | p (undefined :: Float) == x   = return ()
+            | otherwise                     = fail desc
+        
+        assertDoubleProp :: (Monad m, Eq a) => String -> (Double -> a) -> a -> m ()
+        assertDoubleProp desc p x
+            | p (undefined :: Double) == x  = return ()
+            | otherwise                     = fail desc
+    
+    assertFloatProp "Float should ahdere to the IEEE-754 standard" 
+        isIEEE True
+    assertFloatProp "Float's size should be 32 bits"
+        sizeOf 4
+    assertFloatProp "Float should have a base-2 mantissa"
+        floatRadix 2
+    assertFloatProp "Float should have a 23-bit mantissa"
+        floatDigits 24
+    assertFloatProp "Float should have an 8-bit exponent"
+        floatRange (-125, 128)
+    
+    assertDoubleProp "Double should ahdere to the IEEE-754 standard" 
+        isIEEE True
+    assertDoubleProp "Double's size should be 64 bits"
+        sizeOf 8
+    assertDoubleProp "Double should have a base-2 mantissa"
+        floatRadix 2
+    assertDoubleProp "Double should have a 52-bit mantissa"
+        floatDigits 53
+    assertDoubleProp "Double should have an 11-bit exponent"
+        floatRange (-1021, 1024)
+    
+    return []
+ )
+ 
+{- NOINLINE doubleToWord64 -}
+doubleToWord64 :: Double -> Word64
+doubleToWord64 = unsafeConvertStorable
+
+{- NOINLINE word64ToDouble -}
+word64ToDouble :: Word64 -> Double
+word64ToDouble = unsafeConvertStorable
+
+{- NOINLINE floatToWord32 -}
+floatToWord32 :: Float -> Word32
+floatToWord32 = unsafeConvertStorable
+
+{- NOINLINE word32ToFloat -}
+word32ToFloat :: Word32 -> Float
+word32ToFloat = unsafeConvertStorable
+
+{-# INLINE unsafeConvertStorable #-}
+unsafeConvertStorable :: (Storable a, Storable b) => a -> b
+unsafeConvertStorable x = unsafePerformIO $ 
+    alloca $ \p -> do
+        poke (castPtr p) x
+        peek p
+
+doubleToEquivalentFloat :: Double -> Maybe Float
+doubleToEquivalentFloat d
+    -- just check strict equality; if d is NaN, don't convert it
+    -- (in case the NaN has an important payload)
+    | d == d'   = Just f
+    | otherwise = Nothing
+    where
+        f  = double2Float d
+        d' = float2Double f
diff --git a/src/Data/PropertyList/Binary/Get.hs b/src/Data/PropertyList/Binary/Get.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/PropertyList/Binary/Get.hs
@@ -0,0 +1,211 @@
+module Data.PropertyList.Binary.Get where
+
+import Control.Applicative
+import Control.Monad
+import Control.Monad.Trans.Error ({- instance Monad (Either a) -})
+import Data.Bits
+import qualified Data.ByteString.Char8 as BSC8
+import qualified Data.ByteString.Lazy as BL
+import Data.PropertyList.Binary.Float
+import Data.PropertyList.Binary.Types
+import Data.Serialize.Get
+import qualified Data.Sequence as Seq
+import qualified Data.Text as Text
+import qualified Data.Text.Encoding as Text
+import Data.Time
+import qualified Data.Vector.Unboxed as V
+import Data.Word
+import GHC.Float
+
+rawBPList bs = do
+    let headerBS = BL.take 8 bs
+    header@(BPListHeader version) <- runGetLazy bplistHeader headerBS
+    when (version .&. 0xff00 /= 0x3000) $
+        Left "Unsupported bplist version"
+    
+    let trailerBS = BL.drop (BL.length bs - bplistTrailerBytes) bs
+    trailer <- runGetLazy bplistTrailer trailerBS
+    
+    --TODO: sanity checks
+    let nOffsets :: Num a => a
+        nOffsets        = fromIntegral (numObjects trailer)
+        bytesPerOffset  = fromIntegral (offsetIntSize trailer)
+        offsetsBS
+            = BL.take (nOffsets * fromIntegral bytesPerOffset)
+            . BL.drop (fromIntegral (offsetTableOffset trailer))
+            $ bs
+    offsets <- runGetLazy (replicateM nOffsets (sizedInt bytesPerOffset)) offsetsBS
+    
+    return (RawBPList bs header (V.fromList offsets) trailer)
+
+readBPListRecords :: BL.ByteString -> Either String (BPListRecords Abs)
+readBPListRecords bs = do
+    raw <- rawBPList bs
+    let tlr  = rawTrailer raw
+        ct   = numObjects tlr
+        root = topObject tlr
+    recs <- mapM (getBPListRecord raw) [0 .. ct - 1]
+    return (BPListRecords root (Seq.fromList recs))
+
+getBPListRecord (RawBPList bs _hdr offsets tlr) objNum
+    | objNum >= 0 && fromIntegral objNum < V.length offsets
+    = runGetLazy (bplistRecord objRef) (BL.drop (fromIntegral (offsets V.! fromIntegral objNum)) bs)
+    
+    | otherwise = Left "getBPListRecord: index out of range"
+    where
+        objRef = sizedInt (fromIntegral (objectRefSize tlr))
+
+asciiString str = do
+    let bs = BSC8.pack str
+    bs' <- getByteString (BSC8.length bs)
+    if (bs == bs') 
+        then return ()
+        else fail ("Expecting " ++ show str)
+
+bplistHeaderBytes = 8
+bplistHeader = do
+    asciiString "bplist"
+    BPListHeader <$> getWord16be
+
+bplistTrailerBytes = 32
+bplistTrailer =
+    const BPListTrailer
+        <$> skip 5          -- _unused
+        <*> getWord8        -- sortVersion
+        <*> getWord8        -- offsetIntSize
+        <*> getWord8        -- objectRefSize
+        <*> getWord64be     -- numObjects
+        <*> getWord64be     -- topObject
+        <*> getWord64be     -- offsetTableOffset
+
+bplistRecord ref = msum
+    [ const BPLNull     <$> bplNull
+    , BPLBool           <$> bplTrue
+    , BPLBool           <$> bplFalse
+    , const BPLFill     <$> bplFill
+    , BPLInt            <$> bplInt
+    , BPLReal           <$> bplFloat32
+    , BPLReal           <$> bplFloat64
+    , BPLDate           <$> bplDate
+    , BPLData           <$> bplData
+    , BPLString         <$> bplASCII
+    , BPLString         <$> bplUTF16
+    , BPLUID            <$> bplUID
+    , BPLArray          <$> bplArray ref
+    , BPLSet            <$> bplSet ref
+    , uncurry BPLDict   <$> bplDict ref
+    ]
+
+word8 b = do
+    b' <- getWord8
+    if b == b'
+        then return b
+        else fail ("expecting " ++ show b)
+
+bplNull  = word8 0x00
+bplTrue  = word8 0x08 >> return False
+bplFalse = word8 0x09 >> return True
+bplFill  = word8 0x0f
+bplInt = do
+    sz <- shiftL 1 . fromIntegral <$> halfByte 0x1
+    i  <- sizedInt sz
+    return (interpretBPLInt sz i)
+bplFloat32 = do
+    word8 0x22
+    float2Double <$> getFloat32be
+bplFloat64 = do
+    word8 0x23
+    getFloat64be
+bplDate = do
+    word8 0x33
+    interpretBPLDate . word64ToDouble <$> getWord64be
+bplData = do
+    sz <- markerAndSize 0x4
+    getByteString sz
+bplASCII = do
+    sz <- markerAndSize 0x5
+    BSC8.unpack <$> getByteString sz
+bplUTF16 = do
+    sz <- markerAndSize 0x6
+    Text.unpack . Text.decodeUtf16BE <$> getByteString (2*sz)
+bplUID = do
+    sz <- fmap (1+) (halfByte 0x8)
+    sizedInt (fromIntegral sz)
+bplArray ref = do
+    sz <- markerAndSize 0xA
+    replicateM sz ref
+bplSet ref = do
+    sz <- markerAndSize 0xC
+    replicateM sz ref
+bplDict ref = do
+    sz <- markerAndSize 0xD
+    ks <- replicateM sz ref
+    vs <- replicateM sz ref
+    return (ks, vs)
+
+halfByte x = do
+    marker <- getWord8
+    if marker `shiftR` 4 == x
+        then return (marker .&. 0x0f)
+        else fail ("expecting marker " ++ show x)
+markerAndSize x = do
+    marker <- halfByte x
+    case marker of
+        0xf -> do
+            intSz <- shiftL 1 . fromIntegral <$> halfByte 0x1
+            sizedInt intSz
+        _   -> return (fromIntegral marker)
+
+sizedInt :: (Integral i, Bits i) => Word -> Get i
+sizedInt 0 = return 0
+sizedInt 1 = fromIntegral <$> getWord8
+sizedInt 2 = fromIntegral <$> getWord16be
+sizedInt 4 = fromIntegral <$> getWord32be
+sizedInt 8 = fromIntegral <$> getWord64be
+sizedInt n
+    | n < 0     = fail ("sizedInt: negative size: " ++ show n)
+    | otherwise = do
+        let a = n `shiftR` 1; b = n - a
+        x <- sizedInt a
+        y <- sizedInt b
+        return ((x `shiftL` (fromIntegral b * 8)) .|. y)
+
+-- CFBinaryPList.c says:
+{-
+	// in format version '00', 1, 2, and 4-byte integers have to be interpreted as unsigned,
+	// whereas 8-byte integers are signed (and 16-byte when available)
+	// negative 1, 2, 4-byte integers are always emitted as 8 bytes in format '00'
+	// integers are not required to be in the most compact possible representation, but only the last 64 bits are significant currently
+-}
+interpretBPLInt :: Word -> Integer -> Integer
+interpretBPLInt sz i
+    | isSigned && testBit i signBit     = i - bit nBits
+    | otherwise                         = i
+    where
+        isSigned = sz >= 8
+        nBits = fromIntegral sz * 8
+        signBit  = nBits - 1
+
+-- http://developer.apple.com/library/mac/#documentation/CoreFoundation/Reference/CFDateRef/Reference/reference.html 
+-- says:
+{-
+    Absolute time is measured in seconds relative to the absolute reference
+    date of Jan 1 2001 00:00:00 GMT. A positive value represents a date
+    after the reference date, a negative value represents a date before it.
+    For example, the absolute time -32940326 is equivalent to December 16th,
+    1999 at 17:54:34.
+ -}
+interpretBPLDate :: Double -> UTCTime
+interpretBPLDate sec = addUTCTime (realToFrac sec) epoch
+    where
+        epoch = UTCTime (fromGregorian 2001 1 1) 0
+
+getFloat32be :: Get Float
+getFloat32be = do
+    d <- getWord32be
+    return $! word32ToFloat d
+
+getFloat64be :: Get Double
+getFloat64be = do
+    d <- getWord64be
+    return $! word64ToDouble d
diff --git a/src/Data/PropertyList/Binary/Linearize.hs b/src/Data/PropertyList/Binary/Linearize.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/PropertyList/Binary/Linearize.hs
@@ -0,0 +1,64 @@
+module Data.PropertyList.Binary.Linearize
+    ( linearize
+    , absolutize
+    , intern
+    , delinearize
+    ) where
+
+import qualified Data.Foldable as F
+import qualified Data.Map as M
+import Data.Maybe
+import Data.PropertyList.Types
+import Data.PropertyList.Algebra
+import Data.PropertyList.Binary.Algebra ({- instances-})
+import Data.PropertyList.Binary.Types
+import Data.Sequence as S
+import Prelude as P
+
+-- |Flatten a 'PropertyList' to a sequence of 'BPListRecords'.  The resulting records will
+-- use absolute addressing and will not have any duplicates.
+linearize :: PropertyList -> BPListRecords Abs
+linearize = intern . absolutize . fromPlist
+
+-- |Take some 'BPListRecords' using relative addressing and change them to use absolute addressing
+absolutize :: BPListRecords Rel -> BPListRecords Abs
+absolutize (BPListRecords root recs) =
+    BPListRecords root (S.mapWithIndex shiftRec recs)
+    where
+        shiftRec i = mapObjRefs (fromIntegral i +)
+
+-- |Take some 'BPListRecords' using absolute addressing and eliminate 
+-- all duplicate records, compact the table and update all internal
+-- references.
+--
+-- Does not necessarily yield a totally deduplicated table; The process
+-- of interning can introduce duplicate records (because it alters arrays,
+-- dicts and sets).  All other node types will be deduplicated in one pass,
+-- though, which is usually sufficient.
+intern :: BPListRecords Abs -> BPListRecords Abs
+intern (BPListRecords root recs) = BPListRecords (reloc root) recs'
+    where
+        reloc i'
+            | i < 0 || i >= n   = error ("intern: reference out of bounds: " ++ show i)
+            | otherwise         = S.index relocs i
+            where i = fromIntegral i'; n = S.length recs
+        
+        (_, relocs, recs') =
+            F.foldl updateRec (M.empty, S.empty, S.empty) recs
+        
+        updateRec (index, relocs, recs) x = 
+            case M.lookup x index of
+                Nothing -> 
+                    let nRecs = fromIntegral (S.length recs)
+                     in ( M.insert x nRecs index
+                        , relocs |> nRecs
+                        , recs   |> mapObjRefs reloc x
+                        )
+                Just loc ->
+                    ( index, relocs |> loc, recs)
+
+-- TODO: check for cycles?
+-- |Reconstruct a property list from a collection of 'BPListRecords'
+delinearize :: BPListRecords Abs -> PartialPropertyList UnparsedBPListRecord
+delinearize = toPlist
+
diff --git a/src/Data/PropertyList/Binary/Put.hs b/src/Data/PropertyList/Binary/Put.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/PropertyList/Binary/Put.hs
@@ -0,0 +1,184 @@
+module Data.PropertyList.Binary.Put where
+
+import Control.Monad
+import Data.Serialize.Put
+import Data.Bits
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Char8 as BSC8
+import Data.Char
+import Data.Foldable (toList)
+import Data.PropertyList.Binary.Float
+import Data.PropertyList.Binary.Types
+import qualified Data.Sequence as Seq
+import qualified Data.Text as Text
+import qualified Data.Text.Encoding as Text
+import Data.Time
+import Data.Word
+
+withSize putThing = do
+    let thing = runPut putThing
+    putByteString thing
+    return $! (fromIntegral (BS.length thing) :: Word64)
+
+unsnoc []     = error "unsnoc: empty list"
+unsnoc [x]    = ([], x)
+unsnoc (x:xs) = let ~(ys, y) = unsnoc xs in (x:ys, y)
+
+putBPList (BPListRecords root recs) = do
+    let header = bplist00hdr
+        nObjs  = Seq.length recs
+        objRefSz = unsignedSz nObjs
+        putObjRef = putSizedInt objRefSz
+    
+    putBPListHeader header
+    recSizes <- mapM (withSize . putBPListRecord putObjRef) (toList recs)
+    
+    let (offsets, offsetTblLoc) = unsnoc (scanl (+) 8 recSizes)
+        offsetSz        = unsignedSz (offsetTblLoc)
+        putOffset       = putSizedInt (fromIntegral offsetSz)
+        
+        trailer = BPListTrailer 
+            { sortVersion       = 0
+            , offsetIntSize     = fromIntegral offsetSz
+            , objectRefSize     = fromIntegral objRefSz
+            , numObjects        = fromIntegral nObjs
+            , topObject         = root
+            , offsetTableOffset = offsetTblLoc
+            }
+    
+    mapM_ putOffset offsets
+    putBPListTrailer trailer
+
+
+putBPListHeader (BPListHeader v) = do
+    putByteString (BSC8.pack "bplist")
+    putWord16be v
+
+putBPListTrailer tlr = do
+    replicateM 5 (putWord8 0x00)
+    putWord8    (sortVersion       tlr)
+    putWord8    (offsetIntSize     tlr)
+    putWord8    (objectRefSize     tlr)
+    putWord64be (numObjects        tlr)
+    putWord64be (topObject         tlr)
+    putWord64be (offsetTableOffset tlr)
+
+putBPListRecord putRef BPLNull             = putWord8 0x00
+putBPListRecord putRef BPLFill             = putWord8 0x0f
+putBPListRecord putRef (BPLArray     xs)   = do
+    putMarkerWithSize 0xA (length xs)
+    mapM_ putRef xs
+putBPListRecord putRef (BPLSet       xs)   = do
+    putMarkerWithSize 0xC (length xs)
+    mapM_ putRef xs
+putBPListRecord putRef (BPLData       x)   = do
+    putMarkerWithSize 0x4 (BS.length x)
+    putByteString x
+putBPListRecord putRef (BPLDate       x)   = do
+    putWord8 0x33
+    putBPLDate x
+putBPListRecord putRef (BPLDict   ks vs) 
+    | nks /= nvs    = fail "putBPListRecord: BPLDict has different number of keys and values"
+    | otherwise     = do
+        putMarkerWithSize 0xD nks
+        mapM_ putRef ks
+        mapM_ putRef vs
+    where nks = length ks; nvs = length vs
+putBPListRecord putRef (BPLReal       x)   = do
+    case doubleToEquivalentFloat x of
+        Just f -> do
+            putWord8 0x22
+            putFloat32be f
+        Nothing -> do
+            putWord8 0x23
+            putFloat64be x
+putBPListRecord putRef (BPLInt        x)   = putInt x
+putBPListRecord putRef (BPLString     x)   = putString x
+putBPListRecord putRef (BPLUID        x)   = putUID x
+putBPListRecord putRef (BPLBool   False)   = putWord8 0x08
+putBPListRecord putRef (BPLBool    True)   = putWord8 0x09
+
+putMarkerWithPayload x payload = putWord8 ((x `shiftL` 4) .|. payload)
+putMarkerWithSize x sz
+    | sz < 0x0f = do
+        putMarkerWithPayload x (fromIntegral sz)
+    | otherwise = do
+        putMarkerWithPayload x 0x0f
+        putInt (fromIntegral sz)
+
+putInt n
+    | tag < 0       = fail "putInt: internal error - size is negative"
+    | tag <= 0xf    = do
+        putMarkerWithPayload 0x1 (fromIntegral tag)
+        putSizedInt nBytes n
+    | otherwise     = fail "putInt: Integer too large to encode in a bplist00"
+    where (tag, nBytes) = plIntSz n
+
+putSizedInt 0 _ = return ()
+putSizedInt 1 i = putWord8    (fromIntegral i)
+putSizedInt 2 i = putWord16be (fromIntegral i)
+putSizedInt 4 i = putWord32be (fromIntegral i)
+putSizedInt 8 i = putWord64be (fromIntegral i)
+putSizedInt n i
+    | n < 0     = fail "putSizedInt: size is negative"
+    | otherwise = do
+        let a = n `shiftR` 1; b = n - a
+        putSizedInt a (shiftR i (shiftL b 3))
+        putSizedInt b i
+
+-- tag and power-of-two  number of bytes needed to represent 'n' 
+-- as an int.  If the type is bounded, then this logic works for 
+-- negative numbers as well (works for positive but not negative 
+-- 'Integer's)
+wordLgSz n = go 0 8 0xff
+    where
+        go lgSz nBits mask
+            | n .&. mask == n   = (lgSz, shiftR nBits 3)
+            | otherwise         = ((go $! lgSz+1) $! shiftL nBits 1) $! (shiftL mask nBits .|. mask)
+
+-- tag and power-of-two number of bytes needed to represent 'n' as a
+-- 2s-complement signed int
+intLgSz n
+    | n >= 0    = wordLgSz (2 * n)
+    | otherwise = wordLgSz (2 * negate (n+1))
+
+-- tag and number of bytes needed to represent 'n' as a bplist00 int, 
+-- which is has 2^tag bytes and is signed iff it has 8 or more bytes.
+plIntSz :: Integer -> (Int, Int)
+plIntSz n
+    | n < 0      = max (3,8) (intLgSz n)
+    | n < bit 63 = wordLgSz n
+    | otherwise  = intLgSz n
+
+putBPLDate utcDate = putFloat64be (realToFrac (diffUTCTime utcDate epoch))
+    where
+        epoch = UTCTime (fromGregorian 2001 1 1) 0
+
+putString str
+    | all isAscii str   = do
+        putMarkerWithSize 0x5 (length str)
+        putByteString (BSC8.pack str)
+    | otherwise         = do
+        let utf16 = Text.encodeUtf16BE (Text.pack str)
+        putMarkerWithSize 0x6 (BS.length utf16 `shiftR` 1)
+        putByteString utf16
+
+
+putUID i 
+    | sz > maxNBytes    = fail ("putUID: UID is too large (it would require " ++ show sz ++ " bytes to encode, but the bplist00 format only supports " ++ show maxNBytes ++ ")")
+    | otherwise = do
+        putMarkerWithSize 0x8 (sz-1)
+        putSizedInt sz i
+    where
+        sz = unsignedSz i
+        maxNBytes = 16
+
+-- return the number of bytes required to represent an unsigned value.  Always returns at least 1.
+unsignedSz n = go 1 0xff
+    where
+        go nBytes mask
+            | n .&. mask == n   = nBytes
+            | otherwise         = (go $! (nBytes + 1)) $! (shiftL mask 8 .|. mask)
+
+putFloat32be x = putWord32be $! floatToWord32  x
+putFloat64be x = putWord64be $! doubleToWord64 x
diff --git a/src/Data/PropertyList/Binary/Types.hs b/src/Data/PropertyList/Binary/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/PropertyList/Binary/Types.hs
@@ -0,0 +1,67 @@
+{-# LANGUAGE EmptyDataDecls #-}
+module Data.PropertyList.Binary.Types where
+
+import qualified Data.ByteString      as BS (ByteString)
+import qualified Data.ByteString.Lazy as BL (ByteString)
+import Data.Sequence (Seq)
+import Data.Time (UTCTime)
+import Data.Vector.Unboxed (Vector)
+import Data.Word
+
+data BPListRecord
+    = BPLNull
+    | BPLFill
+    | BPLArray [Word64]
+    | BPLSet [Word64]
+    | BPLData BS.ByteString
+    | BPLDate UTCTime
+    | BPLDict [Word64] [Word64]
+    | BPLReal Double
+    | BPLInt Integer
+    | BPLString String
+    | BPLUID Integer
+    | BPLBool Bool
+    deriving (Eq, Ord, Show)
+
+mapObjRefs :: (Word64 -> Word64) -> BPListRecord -> BPListRecord
+mapObjRefs f (BPLArray   xs)  = BPLArray (map f xs)
+mapObjRefs f (BPLSet     xs)  = BPLSet   (map f xs)
+mapObjRefs f (BPLDict ks vs)  = BPLDict  (map f ks) (map f vs)
+mapObjRefs f other = other
+
+data UnparsedBPListRecord
+    = UnparsedNull
+    | UnparsedFill
+    | MissingObjectRef Word64
+    | UnparsedDict [Word64] [Word64]
+    | UnparsedSet [Word64]
+    | UnparsedUID Integer
+    deriving (Eq, Ord, Show)
+
+data Abs
+data Rel
+data BPListRecords mode = BPListRecords
+    { rootObject    :: Word64
+    , records       :: Seq BPListRecord
+    } deriving (Eq, Ord, Show)
+
+data RawBPList = RawBPList
+    { rawFile    :: BL.ByteString
+    , rawHeader  :: BPListHeader
+    , rawOffsets :: Vector Word64
+    , rawTrailer :: BPListTrailer
+    } deriving (Eq, Ord, Show)
+
+newtype BPListHeader = BPListHeader
+    { bplistVersion     :: Word16
+    } deriving (Eq, Ord, Show)
+bplist00hdr = BPListHeader 0x3030
+
+data BPListTrailer = BPListTrailer
+    { sortVersion       :: !Word8
+    , offsetIntSize     :: !Word8
+    , objectRefSize     :: !Word8
+    , numObjects        :: !Word64
+    , topObject         :: !Word64
+    , offsetTableOffset :: !Word64
+    } deriving (Eq, Ord, Show)
diff --git a/src/Data/PropertyList/KeyPath.hs b/src/Data/PropertyList/KeyPath.hs
--- a/src/Data/PropertyList/KeyPath.hs
+++ b/src/Data/PropertyList/KeyPath.hs
@@ -1,19 +1,15 @@
-{-# LANGUAGE
-        ViewPatterns
-  #-}
 module Data.PropertyList.KeyPath 
     ( alterItemAtKeyPathM, alterItemAtKeyPath
     , getItemAtKeyPath, setItemAtKeyPath
     ) where
 
+import Control.Monad
+import Control.Monad.Trans.State
+import Data.Functor.Identity
+import qualified Data.Map as M
 import Data.PropertyList.Algebra
-import Data.PropertyList.Types (PropertyList)
 import Data.PropertyList.PropertyListItem
-
-import qualified Data.Map as M
-
-import Control.Monad.Identity
-import Control.Monad.State
+import Data.PropertyList.Types (PropertyList)
 
 -- |Alter a @'Maybe' 'PropertyList'@, viewing it as an instance of 'PropertyListItem'
 -- and re-synthesizing it from a (possibly different) instance of 'PropertyListItem'.
@@ -75,13 +71,14 @@
     (Monad m, PropertyListItem i, PropertyListItem i') 
     => String -> (Maybe i -> m (Maybe i'))
     -> Maybe PropertyList -> m (Maybe PropertyList)
-tryAlterDictionaryEntryM k f Nothing = do
-    d' <- alterDictionaryEntryM k f Nothing
-    return (fmap plDict d')
-tryAlterDictionaryEntryM k f (Just (fromPlDict -> Just d)) = do
-    d' <- alterDictionaryEntryM k f (Just d)
-    return (fmap plDict d')
-tryAlterDictionaryEntryM k f other = fail "Key path tries to pass through non-dictionary thing."
+tryAlterDictionaryEntryM k f mbPl = 
+    case fmap fromPlDict mbPl of
+        -- outer 'Maybe' is 'Just' if a plist was provided, 
+        -- inner is 'Just' if that plist is a dictionary.
+        Just (Just d)   -> alterDict (Just d)
+        Nothing         -> alterDict Nothing
+        Just Nothing    -> fail "Key path tries to pass through non-dictionary thing."
+    where alterDict = liftM (fmap plDict) . alterDictionaryEntryM k f
 
 -- |@alterItemAtKeyPathM path f@ applies the function @f@ deep inside the 
 -- 'PropertyList' on the property list item at the given key-path @path@
diff --git a/src/Data/PropertyList/PropertyListItem.hs b/src/Data/PropertyList/PropertyListItem.hs
--- a/src/Data/PropertyList/PropertyListItem.hs
+++ b/src/Data/PropertyList/PropertyListItem.hs
@@ -1,6 +1,5 @@
 {-# LANGUAGE
     MultiParamTypeClasses,
-    TypeSynonymInstances,
     FlexibleInstances,
     TemplateHaskell, CPP,
     ViewPatterns
@@ -11,24 +10,23 @@
 
 import Language.Haskell.TH
 import Language.Haskell.TH.Syntax
-import Language.Haskell.TH.Fold
 
 import Data.PropertyList.Algebra
 import Data.PropertyList.Types
 
 import qualified Data.Map as M
-import Data.ByteString (ByteString)
-import qualified Data.ByteString.Lazy as Lazy (ByteString)
-import Data.ByteString.Class
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as BL
 import Data.Time
 import Data.Char
 import Data.Int
+import qualified Data.Text as Text
 import Data.Word
 
-import Text.XML.HaXml.OneOfN
+import Data.OneOfN
 
 import Control.Monad
-import Control.Monad.Identity
+import Data.Functor.Identity
 import qualified Data.Traversable as Traversable
 import Data.Generics
 
@@ -48,6 +46,11 @@
     (i, 0) -> Just i
     _ -> Nothing
 
+toStrictByteString :: BL.ByteString -> BS.ByteString
+toStrictByteString = BS.concat . BL.toChunks
+toLazyByteString :: BS.ByteString -> BL.ByteString
+toLazyByteString = BL.fromChunks . return
+
 -- |A class for items which can be converted to and from property lists.  This
 -- is more general than 'PListAlgebra' and 'PListCoalgebra', in that it allows
 -- for transformations that are not primitive-recursive.  This relaxation is
@@ -94,16 +97,16 @@
     toPropertyList = id
     fromPropertyList = Just
 
-instance PropertyListItem ByteString where
+instance PropertyListItem BS.ByteString where
     toPropertyList = plData
     fromPropertyList (fromPlData    -> Just x) = Just x
-    fromPropertyList (fromPlString  -> Just x) = Just (toStrictByteString x)
+--    fromPropertyList (fromPlString  -> Just x) = Just (toStrictByteString x)
     fromPropertyList _ = Nothing
 
-instance PropertyListItem Lazy.ByteString where
+instance PropertyListItem BL.ByteString where
     toPropertyList = plData . toStrictByteString
     fromPropertyList (fromPlData    -> Just x) = Just (toLazyByteString x)
-    fromPropertyList (fromPlString  -> Just x) = Just (toLazyByteString x)
+--    fromPropertyList (fromPlString  -> Just x) = Just (toLazyByteString x)
     fromPropertyList _ = Nothing
 
 instance PropertyListItem UTCTime where
@@ -163,13 +166,17 @@
     
     listToPropertyList = plString
     listFromPropertyList (fromPlString -> Just x)     = Just x
-    listFromPropertyList (fromPlData   -> Just x)     = Just (fromStrictByteString x)
+--    listFromPropertyList (fromPlData   -> Just x)     = Just (fromStrictByteString x)
     listFromPropertyList (fromPlBool   -> Just True)  = Just "YES"
     listFromPropertyList (fromPlBool   -> Just False) = Just "NO"
     listFromPropertyList (fromPlInt    -> Just i)     = Just (show i)
     listFromPropertyList (fromPlReal   -> Just d)     = Just (show d)
     listFromPropertyList other = Nothing
 
+instance PropertyListItem Text.Text where
+    toPropertyList = toPropertyList . Text.unpack
+    fromPropertyList = fmap Text.pack . fromPropertyList
+
 instance PropertyListItem Bool where
     toPropertyList = plBool
     fromPropertyList (fromPlBool   -> Just d) = Just d
@@ -184,7 +191,7 @@
 --  (N in [2..20]), an instance of the form:
 -- 
 -- instance (PropertyListItem a, PropertyListItem b, PropertyListItem c) => PropertyListItem (OneOf3 a b c) where
---     toPropertyList = $(fold ''OneOf3) toPropertyList toPropertyList toPropertyList
+--     toPropertyList = oneOf3 toPropertyList toPropertyList toPropertyList
 --     fromPropertyList pl = msum [ fmap OneOf3 (fromPropertyList pl)
 --                                , fmap TwoOf3 (fromPropertyList pl)
 --                                , fmap ThreeOf3 (fromPropertyList pl)
@@ -220,6 +227,8 @@
                     , funD 'fromPropertyList [clause [varP pl] (normalB fromPLbody) []]
                     ]
                 
+                lcFirst (c:cs) = toLower c : cs
+                fold  = varE . mkName . lcFirst . nameBase
                 toPLbody = appsE (fold typeName : map (const (varE 'toPropertyList)) conNames)
                 fromPLbody = appE (varE 'msum) $ listE
                     [ [| fmap $(conE con) (fromPropertyList $(varE pl)) |]
diff --git a/src/Data/PropertyList/Types.hs b/src/Data/PropertyList/Types.hs
--- a/src/Data/PropertyList/Types.hs
+++ b/src/Data/PropertyList/Types.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE 
     MultiParamTypeClasses,
-    FlexibleContexts, FlexibleInstances, IncoherentInstances,
-    GeneralizedNewtypeDeriving
+    FlexibleContexts, FlexibleInstances,
+    GeneralizedNewtypeDeriving, TypeFamilies
   #-}
 
 -- |This module implements the 'PropertyList' and 'PartialPropertyList' types
@@ -30,14 +30,12 @@
 
 import Control.Applicative      (Applicative(..))
 import Data.Functor.Foldable    (Fix(..))
-import Data.Pointed             (Pointed(..))
-import Data.Copointed           (Copointed(..))
+import qualified Data.Functor.Foldable as RS
 import Control.Monad            (liftM)
 import Control.Monad.Free       (Free(..))
-import Control.Monad.Identity   (Identity(..))
+import Data.Functor.Identity    (Identity(..))
 import Data.Foldable            (Foldable)
 import Data.Traversable         (Traversable(traverse), mapM)
-import Data.Void                (Void, absurd)
 
 import Unsafe.Coerce            (unsafeCoerce) {- used _only_ to eliminate fmap traversals for newtype constructors -}
 
@@ -63,19 +61,30 @@
         PLString str  -> showString "plString " . showsPrec 11 str 
         PLBool   bool -> showString "plBool "   . showsPrec 11 bool
 
-instance (Functor f, Copointed f) => PListAlgebra f PropertyList where
-    {-# SPECIALIZE instance PListAlgebra Identity PropertyList #-}
-    plistAlgebra = PL . Fix . fmap unPL . copoint
+type instance RS.Base PropertyList = PropertyListS
+instance RS.Foldable PropertyList where
+    project = runIdentity . plistCoalgebra
+instance RS.Unfoldable PropertyList where
+    embed = plistAlgebra . Identity
 
+inPL :: PropertyListS PropertyList -> PropertyList
+inPL = PL . Fix . fmap unPL
+
+outPL :: PropertyList -> PropertyListS PropertyList
+outPL = fmap PL . outF . unPL
+    where outF (Fix x) = x
+
+instance PListAlgebra Identity PropertyList where
+    plistAlgebra = inPL . runIdentity
+
 instance PListCoalgebra Identity a => PListAlgebra (Either a) PropertyList where
     plistAlgebra = either toPlist (plistAlgebra . Identity)
 
 instance InitialPList Identity PropertyList
 
-instance (Functor f, Pointed f) => PListCoalgebra f PropertyList where
+instance Applicative f => PListCoalgebra f PropertyList where
     {-# SPECIALIZE instance PListCoalgebra Identity PropertyList #-}
-    plistCoalgebra = point . fmap PL . outF . unPL
-        where outF (Fix x) = x
+    plistCoalgebra = pure . outPL
 
 instance TerminalPList Identity PropertyList
 
@@ -90,9 +99,6 @@
   #-}
 
 
-instance Pointed PartialPropertyList where
-    point = PPL . Pure
-
 -- | [internal] 'Free' constructor specialized to 'PartialPropertyList'.
 -- 'point'/'pure'/'return' is the corresponding 'Pure' constructor.
 inPPL :: PropertyListS (PartialPropertyList a) -> PartialPropertyList a
@@ -114,20 +120,14 @@
 -- instance Read...
 
 
--- this instance overlaps (with incoherence allowed) with all 
--- others for PartialPropertyList: ensure that you don't define 
--- an explicit instance for any 'Copointed' functor!
-instance (Functor f, Copointed f) => PListAlgebra f (PartialPropertyList a) where
-    {-# SPECIALIZE instance PListAlgebra Identity (PartialPropertyList a) #-}
-    plistAlgebra = inPPL . copoint
+instance PListAlgebra Identity (PartialPropertyList a) where
+    plistAlgebra = inPPL . runIdentity
 
 instance PListAlgebra Maybe (PartialPropertyList ()) where
-    plistAlgebra Nothing  = point ()
-    plistAlgebra (Just x) = inPPL x
+    plistAlgebra = maybe (pure ()) inPPL
 
 instance PListAlgebra (Either a) (PartialPropertyList a) where
-    plistAlgebra (Left  x) = point x
-    plistAlgebra (Right x) = inPPL x
+    plistAlgebra = either pure inPPL
 
 instance InitialPList (Either a) (PartialPropertyList a) where
 
@@ -178,7 +178,3 @@
 completePropertyListByM :: (Monad m, PListCoalgebra Identity b)
     => (a -> m b) -> PartialPropertyList a -> m PropertyList
 completePropertyListByM f = liftM completePropertyList . Data.Traversable.mapM f
-
--- instance for Void to allow it to be used as @a@ in 'completePropertyList':
-instance Functor f => PListCoalgebra f Void where
-    plistCoalgebra = absurd
diff --git a/src/Data/PropertyList/Xml.hs b/src/Data/PropertyList/Xml.hs
--- a/src/Data/PropertyList/Xml.hs
+++ b/src/Data/PropertyList/Xml.hs
@@ -1,16 +1,7 @@
-{-# LANGUAGE
-        FlexibleContexts
-  #-}
+{-# LANGUAGE FlexibleContexts #-}
 module Data.PropertyList.Xml
-    ( Plist
-    , readXmlPlist, showXmlPlist
-    , readXmlPlistFromFile, writeXmlPlistToFile
-    
-    , PlistItem
-    , plistToPlistItem, plistItemToPlist
-    
-    , UnparsedPlistItem(..)
-    , unparsedPlistItemToPlistItem
+    ( UnparsedXmlPlistItem(..)
+    , unparsedXmlPlistItemToElement
     
     , readXmlPropertyList, readXmlPropertyListFromFile
     
@@ -19,88 +10,74 @@
     
     ) where
 
-import Data.Copointed
+import Control.Monad.Trans.Error ({- instance Monad (Either a) -})
 import Data.PropertyList.Algebra
 import Data.PropertyList.Types
-import Data.PropertyList.Xml.Parse
-import Data.PropertyList.Xml.Types
-
-import Control.Monad.Error ({- instance Monad (Either String) -})
-
--- * Reading and writing XML 'Plist's from files
-
--- |Try to parse a 'Plist' from an XML property-list file.
-readXmlPlistFromFile :: FilePath -> IO (Either String Plist)
-readXmlPlistFromFile path = do
-        contents <- readFile path
-        return (readXmlPlist contents)
-
--- |Try to write a 'Plist' to an XML property-list file.
-writeXmlPlistToFile :: FilePath -> Plist -> IO ()
-writeXmlPlistToFile path plist = do
-        writeFile path (showXmlPlist plist)
-
+import Data.PropertyList.Xml.Algebra
+import Text.XML.Light
 
 -- * Reading and writing XML 'PartialPropertyList's and 'PropertyList's from 'String's
 
--- |Read an XML propertylist from a 'String' in the xml1 plist format to a
--- propertylist type which is terminal for the liftings supported by
--- 'PlistItem'  (such as @'PartialPropertyList' 'UnparsedPlistItem'@
--- or @'PartialPropertyList' 'PlistItem'@).
-readXmlPartialPropertyList :: (PListCoalgebra f PlistItem, TerminalPList f pl) => String -> Either String pl
-readXmlPartialPropertyList = fmap (toPlist . plistToPlistItem) . readXmlPlist
+-- |Read an XML property list from a 'String' in the xml1 plist format, leaving 
+-- unparseable elements in the tree.
+readXmlPartialPropertyList :: String -> Either String (PartialPropertyList UnparsedXmlPlistItem)
+readXmlPartialPropertyList str = case parseXMLDoc str of
+    Just e@(Element (QName "plist" _ _) _ content _) ->
+        let v = plistVersion e
+         in if v == "1.0"
+                then case onlyElems content of
+                    [root]  -> Right (toPlist root)
+                    _       -> Left "plist element must have exactly one child element"
+                else Left ("plist version " ++ show v ++ " is not supported")
+    Just e  -> Right (toPlist e)
+    Nothing -> Left "not an XML document"
+    where
+        plistVersion = maybe "1.0" id . findAttrBy isVersion
+        
+        isVersion (QName "version" _ _) = True
+        isVersion _ = False
 
 -- |Read a property list from a 'String' in the xml1 format.  If parsing
 -- fails, returns a description of the problem in the 'Left' result.
-readXmlPropertyList :: FilePath -> Either String PropertyList
-readXmlPropertyList str = do
-    x <- readXmlPartialPropertyList str :: Either String (PartialPropertyList UnparsedPlistItem)
-    completePropertyListByM (\unparsed -> Left ("Unparseable item found: " ++ show unparsed) :: Either String PropertyList) x
-
---readXmlPropertyList :: String -> PropertyList
---readXmlPropertyList
---    = runIdentity
---    . completePropertyListByM (\_ -> fail "parse error" :: Identity PropertyList)
---    . either error id
---    . (readXmlPartialPropertyList :: String -> Either String (PartialPropertyList UnparsedPlistItem))
+readXmlPropertyList :: String -> Either String PropertyList
+readXmlPropertyList str
+    =   readXmlPartialPropertyList str 
+    >>= completePropertyListByM barf
+        where barf unparsed = Left ("Unparseable item found: " ++ show unparsed) :: Either String PropertyList
 
 -- |Render a propertylist to a 'String' in the xml1 plist format from any
 -- initial propertylist type  (which includes 'PropertyList', @'PartialPropertyList'
 -- 'UnparsedPlistItem'@, and @'PartialPropertyList' 'PlistItem'@).
-showXmlPropertyList :: (InitialPList f pl, Functor f, Copointed f) => pl -> String
-showXmlPropertyList
-    = showXmlPlist
-    . plistItemToPlist
-    . fromPlist
-
+showXmlPropertyList :: (InitialPList f pl, PListAlgebra f Element) => pl -> String
+showXmlPropertyList = ppTopElement . plist1element . fromPlist
+    where
+        version1attr = Attr (unqual "version") "1.0"
+        plist1element :: Element -> Element
+        plist1element root = unode "plist" (version1attr, root)
+    
 
 -- * Reading and writing XML 'PartialPropertyList's and 'PropertyList's from files
 
 -- |Read an XML propertylist from a file in the xml1 plist format to a
--- propertylist type which is terminal for the liftings supported by
--- 'PlistItem'  (such as @'PartialPropertyList' 'UnparsedPlistItem'@
--- or @'PartialPropertyList' 'PlistItem'@).
+-- partial propertylist which is structurally sound but may contain some 
+-- unparseable nodes.
 readXmlPartialPropertyListFromFile
-  :: (PListCoalgebra f PlistItem, TerminalPList f pl) =>
-     FilePath -> IO (Either String pl)
+  :: FilePath -> IO (PartialPropertyList UnparsedXmlPlistItem)
 readXmlPartialPropertyListFromFile file = do
-        x <- readXmlPlistFromFile file
-        return (fmap (toPlist . plistToPlistItem) x)
+    x <- readFile file
+    either fail return (readXmlPartialPropertyList x)
 
 -- |Read a property list from a file in the xml1 format.  If parsing fails,
 -- calls 'fail'.
 readXmlPropertyListFromFile :: FilePath -> IO PropertyList
 readXmlPropertyListFromFile file = do
-    x <- readXmlPartialPropertyListFromFile file :: IO (Either String (PartialPropertyList UnparsedPlistItem))
-    y <- either fail return x
-    completePropertyListByM (\unparsed -> fail ("Unparseable item found: " ++ show unparsed) :: IO PropertyList) y
+    x <- readFile file
+    either fail return (readXmlPropertyList x)
     
 
 -- |Output a propertylist to a file in the xml1 plist format from any
 -- initial propertylist type  (which includes 'PropertyList', @'PartialPropertyList'
 -- 'UnparsedPlistItem'@, and @'PartialPropertyList' 'PlistItem'@).
-writeXmlPropertyListToFile
-  :: (InitialPList f pl, Functor f, Copointed f) =>
-     FilePath -> pl -> IO ()
-writeXmlPropertyListToFile file plist = do
-        writeXmlPlistToFile file (plistItemToPlist (fromPlist plist))
+writeXmlPropertyListToFile :: FilePath -> PropertyList -> IO ()
+writeXmlPropertyListToFile file plist =
+    writeFile file (showXmlPropertyList plist)
diff --git a/src/Data/PropertyList/Xml/Algebra.hs b/src/Data/PropertyList/Xml/Algebra.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/PropertyList/Xml/Algebra.hs
@@ -0,0 +1,133 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleInstances #-}
+module Data.PropertyList.Xml.Algebra
+    ( UnparsedXmlPlistItem(..)
+    , unparsedXmlPlistItemToElement
+    ) where
+
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Char8 as BSC8
+import qualified Data.ByteString.Base64 as B64
+import Data.Char (isSpace)
+import Data.Functor.Identity
+import qualified Data.Map as M
+import Data.PropertyList.Algebra
+import Data.Time
+import System.Locale
+import Text.XML.Light
+
+-- "%FT%T%QZ" would be better, but apple's plist parser
+-- doesn't accept the fractional-seconds part.
+dateFormat :: String
+dateFormat = "%FT%T%QZ"
+
+b64encode :: BS.ByteString -> String
+b64encode = BSC8.unpack . B64.encode
+
+instance PListAlgebra Identity Element where
+    plistAlgebra = toElem . runIdentity
+        where
+            toElem :: PropertyListS Element -> Element
+            toElem (PLArray    x) = unode "array" x
+            toElem (PLData     x) = unode "data" (b64encode x)
+            toElem (PLDate     x) = unode "date" (formatTime defaultTimeLocale dateFormat x)
+            toElem (PLDict     x) = unode "dict" $ concat
+                [ [ unode "key" k, v]
+                | (k,v) <- M.toAscList x
+                ]
+            toElem (PLReal     x) = unode "real"    (show x)
+            toElem (PLInt      x) = unode "integer" (show x)
+            toElem (PLString   x) = unode "string"  x
+            toElem (PLBool  True) = unode "true"    ()
+            toElem (PLBool False) = unode "false"   ()
+
+-- |A representation of values that were structurally sound in the 
+-- property list file but the contents of which couldn't be interpreted
+-- as what they claimed to be.  The result of the initial parse phase will
+-- typically be a @PartialPropertyList UnparsedXmlPlistItem@, and if
+-- the whole plist was parsed properly will contain no actual values 
+-- of this type.
+data UnparsedXmlPlistItem
+    = UnparsedData String
+    | UnparsedDate String
+    | UnparsedInt  String
+    | UnparsedReal String
+    | UnparsedXml Element
+    deriving Show
+
+unparsedXmlPlistItemToElement = toElem
+    where
+        toElem (UnparsedData x) = unode "data"    x
+        toElem (UnparsedDate x) = unode "date"    x
+        toElem (UnparsedInt  x) = unode "integer" x
+        toElem (UnparsedReal x) = unode "real"    x
+        toElem (UnparsedXml  e) = e
+
+b64decode :: String -> Either String BS.ByteString
+b64decode = B64.decode . BSC8.pack . filter (not . isSpace)
+
+instance PListAlgebra (Either Element) Element where
+    plistAlgebra (Left x) = x
+    plistAlgebra (Right x) = plistAlgebra (Identity x)
+
+instance PListAlgebra (Either UnparsedXmlPlistItem) Element where
+    plistAlgebra (Left x) = unparsedXmlPlistItemToElement x
+    plistAlgebra (Right x) = plistAlgebra (Identity x)
+
+instance PListCoalgebra (Either UnparsedXmlPlistItem) Element where
+    -- I can't find any info anywhere about what namespace URI, if any, should
+    -- be used for XML property lists.  So, ignoring it.
+    plistCoalgebra e = coalg e
+        where
+            coalg (Element (QName name _ _) [] content _) = fromElem name content
+            coalg _ = reject UnparsedXml e
+            
+            fromElem "array" content
+                = accept PLArray (onlyElems content)
+            fromElem "data" content
+                = let contentText = text content
+                   in case b64decode contentText of
+                        Right xs -> accept PLData xs
+                        Left  _  -> reject UnparsedData contentText
+            fromElem "date" content
+                = let contentText = text content
+                   in case parseTime defaultTimeLocale dateFormat contentText of
+                        Nothing -> reject UnparsedDate contentText
+                        Just x  -> accept PLDate x
+            fromElem "dict" content
+                = fmap (PLDict . M.fromList) (fromDict (onlyElems content))
+            fromElem "real" content
+                = tryRead PLReal UnparsedReal (text content)
+            fromElem "integer" content
+                = tryRead PLInt UnparsedInt (text content)
+            fromElem "string" content
+                = accept PLString (text content)
+            fromElem "true"  [] = accept PLBool True
+            fromElem "false" [] = accept PLBool False
+            fromElem _ _ = reject UnparsedXml e
+            
+            fromDict [] = Right []
+            fromDict (key : value : rest)
+                = case key of
+                    Element (QName "key" _ _) [] content _
+                        -> fmap ((text content, value) :) (fromDict rest)
+                    _   -> reject UnparsedXml e
+            
+            text = concatMap cdData . onlyText
+            
+            accept :: (a -> c) -> a -> Either b c
+            accept con = Right . con
+            
+            reject :: (a -> b) -> a -> Either b c
+            reject con = Left  . con
+            
+            tryRead :: Read a => (a -> c) -> (String -> b) -> String -> Either b c
+            tryRead onGood onBad str =
+                    case reads str of
+                            ((result, ""):_) -> accept onGood result
+                            _                -> reject onBad  str
+
+instance PListCoalgebra Maybe Element where
+    plistCoalgebra
+        = either (const Nothing :: UnparsedXmlPlistItem -> Maybe a) Just
+        . plistCoalgebra
diff --git a/src/Data/PropertyList/Xml/Dtd.hs b/src/Data/PropertyList/Xml/Dtd.hs
deleted file mode 100644
--- a/src/Data/PropertyList/Xml/Dtd.hs
+++ /dev/null
@@ -1,204 +0,0 @@
-{-
- -      generated by DtdToHaskell (from HaXml 1.19.4)
- -      altered to fix ambiguities (added explicit Prelude imports)
- -}
-
-module Data.PropertyList.Xml.Dtd where
-
-import Prelude ((++), ($), return, Eq, Show, String, concatMap)
-
-import Text.XML.HaXml.XmlContent
-import Text.XML.HaXml.OneOfN
-
-{-Type decls-}
-
--- |DtdToHaskell-generated type representing XML trees that match the PropertyList-1.0 dtd.
--- This is an opaque representation of a structurally-sound property list
--- which might still contain invalid data.  End users should never need to
--- use this type, but if they do, it can be manipulated with the constructors
--- and deconstructors in "Data.PropertyList.Algebra".
-data Plist = PlistArray Plist_Attrs Array
-           | PlistData Plist_Attrs Data
-           | PlistDate Plist_Attrs Date
-           | PlistDict Plist_Attrs Dict
-           | PlistAReal Plist_Attrs AReal
-           | PlistAInteger Plist_Attrs AInteger
-           | PlistAString Plist_Attrs AString
-           | PlistTrue Plist_Attrs True
-           | PlistFalse Plist_Attrs False
-           deriving (Eq,Show)
-data Plist_Attrs = Plist_Attrs
-    { plistVersion :: (Defaultable String)
-    } deriving (Eq,Show)
-newtype Array = Array [(OneOf9 Array Data Date Dict AReal AInteger AString True False)] 		deriving (Eq,Show)
-newtype Dict = Dict [Dict_] 		deriving (Eq,Show)
-data Dict_ = Dict_ Key
-                   (OneOf9 Array Data Date Dict AReal AInteger AString True False)
-           deriving (Eq,Show)
-newtype Key = Key String 		deriving (Eq,Show)
-newtype AString = AString String 		deriving (Eq,Show)
-newtype Data = Data String 		deriving (Eq,Show)
-newtype Date = Date String 		deriving (Eq,Show)
-data True = True 		deriving (Eq,Show)
-data False = False 		deriving (Eq,Show)
-newtype AReal = AReal String 		deriving (Eq,Show)
-newtype AInteger = AInteger String 		deriving (Eq,Show)
-
-
-{-Instance decls-}
-
-instance HTypeable Plist where
-    toHType x = Defined "plist" [] []
-instance XmlContent Plist where
-    toContents (PlistArray as a) =
-        [CElem (Elem "plist" (toAttrs as) (toContents a) ) ()]
-    toContents (PlistData as a) =
-        [CElem (Elem "plist" (toAttrs as) (toContents a) ) ()]
-    toContents (PlistDate as a) =
-        [CElem (Elem "plist" (toAttrs as) (toContents a) ) ()]
-    toContents (PlistDict as a) =
-        [CElem (Elem "plist" (toAttrs as) (toContents a) ) ()]
-    toContents (PlistAReal as a) =
-        [CElem (Elem "plist" (toAttrs as) (toContents a) ) ()]
-    toContents (PlistAInteger as a) =
-        [CElem (Elem "plist" (toAttrs as) (toContents a) ) ()]
-    toContents (PlistAString as a) =
-        [CElem (Elem "plist" (toAttrs as) (toContents a) ) ()]
-    toContents (PlistTrue as a) =
-        [CElem (Elem "plist" (toAttrs as) (toContents a) ) ()]
-    toContents (PlistFalse as a) =
-        [CElem (Elem "plist" (toAttrs as) (toContents a) ) ()]
-    parseContents = do 
-        { e@(Elem _ as _) <- element ["plist"]
-        ; interior e $ oneOf
-            [ return (PlistArray (fromAttrs as)) `apply` parseContents
-            , return (PlistData (fromAttrs as)) `apply` parseContents
-            , return (PlistDate (fromAttrs as)) `apply` parseContents
-            , return (PlistDict (fromAttrs as)) `apply` parseContents
-            , return (PlistAReal (fromAttrs as)) `apply` parseContents
-            , return (PlistAInteger (fromAttrs as)) `apply` parseContents
-            , return (PlistAString (fromAttrs as)) `apply` parseContents
-            , return (PlistTrue (fromAttrs as)) `apply` parseContents
-            , return (PlistFalse (fromAttrs as)) `apply` parseContents
-            ] `adjustErr` ("in <plist>, "++)
-        }
-instance XmlAttributes Plist_Attrs where
-    fromAttrs as =
-        Plist_Attrs
-          { plistVersion = defaultA fromAttrToStr "1.0" "version" as
-          }
-    toAttrs v = catMaybes 
-        [ defaultToAttr toAttrFrStr "version" (plistVersion v)
-        ]
-
-instance HTypeable Array where
-    toHType x = Defined "array" [] []
-instance XmlContent Array where
-    toContents (Array a) =
-        [CElem (Elem "array" [] (concatMap toContents a)) ()]
-    parseContents = do
-        { e@(Elem _ [] _) <- element ["array"]
-        ; interior e $ return (Array) `apply` many parseContents
-        } `adjustErr` ("in <array>, "++)
-
-instance HTypeable Dict where
-    toHType x = Defined "dict" [] []
-instance XmlContent Dict where
-    toContents (Dict a) =
-        [CElem (Elem "dict" [] (concatMap toContents a)) ()]
-    parseContents = do
-        { e@(Elem _ [] _) <- element ["dict"]
-        ; interior e $ return (Dict) `apply` many parseContents
-        } `adjustErr` ("in <dict>, "++)
-
-instance HTypeable Dict_ where
-    toHType x = Defined "dict" [] []
-instance XmlContent Dict_ where
-    toContents (Dict_ a b) =
-        (toContents a ++ toContents b)
-    parseContents = return (Dict_) `apply` parseContents
-                    `apply` parseContents
-
-instance HTypeable Key where
-    toHType x = Defined "key" [] []
-instance XmlContent Key where
-    toContents (Key a) =
-        [CElem (Elem "key" [] (toText a)) ()]
-    parseContents = do
-        { e@(Elem _ [] _) <- element ["key"]
-        ; interior e $ return (Key) `apply` (text `onFail` return "")
-        } `adjustErr` ("in <key>, "++)
-
-instance HTypeable AString where
-    toHType x = Defined "string" [] []
-instance XmlContent AString where
-    toContents (AString a) =
-        [CElem (Elem "string" [] (toText a)) ()]
-    parseContents = do
-        { e@(Elem _ [] _) <- element ["string"]
-        ; interior e $ return (AString) `apply` (text `onFail` return "")
-        } `adjustErr` ("in <string>, "++)
-
-instance HTypeable Data where
-    toHType x = Defined "data" [] []
-instance XmlContent Data where
-    toContents (Data a) =
-        [CElem (Elem "data" [] (toText a)) ()]
-    parseContents = do
-        { e@(Elem _ [] _) <- element ["data"]
-        ; interior e $ return (Data) `apply` (text `onFail` return "")
-        } `adjustErr` ("in <data>, "++)
-
-instance HTypeable Date where
-    toHType x = Defined "date" [] []
-instance XmlContent Date where
-    toContents (Date a) =
-        [CElem (Elem "date" [] (toText a)) ()]
-    parseContents = do
-        { e@(Elem _ [] _) <- element ["date"]
-        ; interior e $ return (Date) `apply` (text `onFail` return "")
-        } `adjustErr` ("in <date>, "++)
-
-instance HTypeable True where
-    toHType x = Defined "true" [] []
-instance XmlContent True where
-    toContents True =
-        [CElem (Elem "true" [] []) ()]
-    parseContents = do
-        { (Elem _ as []) <- element ["true"]
-        ; return True
-        } `adjustErr` ("in <true>, "++)
-
-instance HTypeable False where
-    toHType x = Defined "false" [] []
-instance XmlContent False where
-    toContents False =
-        [CElem (Elem "false" [] []) ()]
-    parseContents = do
-        { (Elem _ as []) <- element ["false"]
-        ; return False
-        } `adjustErr` ("in <false>, "++)
-
-instance HTypeable AReal where
-    toHType x = Defined "real" [] []
-instance XmlContent AReal where
-    toContents (AReal a) =
-        [CElem (Elem "real" [] (toText a)) ()]
-    parseContents = do
-        { e@(Elem _ [] _) <- element ["real"]
-        ; interior e $ return (AReal) `apply` (text `onFail` return "")
-        } `adjustErr` ("in <real>, "++)
-
-instance HTypeable AInteger where
-    toHType x = Defined "integer" [] []
-instance XmlContent AInteger where
-    toContents (AInteger a) =
-        [CElem (Elem "integer" [] (toText a)) ()]
-    parseContents = do
-        { e@(Elem _ [] _) <- element ["integer"]
-        ; interior e $ return (AInteger) `apply` (text `onFail` return "")
-        } `adjustErr` ("in <integer>, "++)
-
-
-
-{-Done-}
diff --git a/src/Data/PropertyList/Xml/Dtd_1_13.hs b/src/Data/PropertyList/Xml/Dtd_1_13.hs
deleted file mode 100644
--- a/src/Data/PropertyList/Xml/Dtd_1_13.hs
+++ /dev/null
@@ -1,212 +0,0 @@
-{-
- -      generated by DtdToHaskell (from HaXml 1.13.3)
- -      altered to fix ambiguities and build errors
- -       (why is this the "preferred" HaXml version, anyway?)
- -}
-
-module Data.PropertyList.Xml.Dtd_1_13 where
-
-import Text.XML.HaXml.Xml2Haskell
-import Text.XML.HaXml.OneOfN
-import Data.Char (isSpace)
-
-import Prelude (Eq, Show, String, Maybe(..), all, concatMap, (++))
-
-{-Type decls-}
-
--- |DtdToHaskell-generated type representing XML trees that match the PropertyList-1.0 dtd.
--- This is an opaque representation of a structurally-sound property list
--- which might still contain invalid data.  End users should never need to
--- use this type, but if they do, it can be manipulated with the constructors
--- and deconstructors in "Data.PropertyList.Algebra".
-data Plist = PlistArray Plist_Attrs Array
-           | PlistData Plist_Attrs Data
-           | PlistDate Plist_Attrs Date
-           | PlistDict Plist_Attrs Dict
-           | PlistAReal Plist_Attrs AReal
-           | PlistAInteger Plist_Attrs AInteger
-           | PlistAString Plist_Attrs AString
-           | PlistTrue Plist_Attrs True
-           | PlistFalse Plist_Attrs False
-           deriving (Eq,Show)
-data Plist_Attrs = Plist_Attrs
-    { plistVersion :: (Defaultable String)
-    } deriving (Eq,Show)
-newtype Array = Array [(OneOf9 Array Data Date Dict AReal AInteger AString True False)] 		deriving (Eq,Show)
-newtype Dict = Dict [Dict_] 		deriving (Eq,Show)
-data Dict_ = Dict_ Key
-                   (OneOf9 Array Data Date Dict AReal AInteger AString True False)
-           deriving (Eq,Show)
-newtype Key = Key String 		deriving (Eq,Show)
-newtype AString = AString String 		deriving (Eq,Show)
-newtype Data = Data String 		deriving (Eq,Show)
-newtype Date = Date String 		deriving (Eq,Show)
-data True = True 		deriving (Eq,Show)
-data False = False 		deriving (Eq,Show)
-newtype AReal = AReal String 		deriving (Eq,Show)
-newtype AInteger = AInteger String 		deriving (Eq,Show)
-
-
-{-Instance decls-}
-
-instance XmlContent Plist where
-    fromElem (CElem (Elem "plist" as c0):rest) =
-        case (fromElem c0) of
-        (Just a,_) -> (Just (PlistArray (fromAttrs as) a), rest)
-        (_,_) ->
-                case (fromElem c0) of
-                (Just a,_) -> (Just (PlistData (fromAttrs as) a), rest)
-                (_,_) ->
-                        case (fromElem c0) of
-                        (Just a,_) -> (Just (PlistDate (fromAttrs as) a), rest)
-                        (_,_) ->
-                                case (fromElem c0) of
-                                (Just a,_) -> (Just (PlistDict (fromAttrs as) a), rest)
-                                (_,_) ->
-                                        case (fromElem c0) of
-                                        (Just a,_) -> (Just (PlistAReal (fromAttrs as) a), rest)
-                                        (_,_) ->
-                                                case (fromElem c0) of
-                                                (Just a,_) -> (Just (PlistAInteger (fromAttrs as) a), rest)
-                                                (_,_) ->
-                                                        case (fromElem c0) of
-                                                        (Just a,_) -> (Just (PlistAString (fromAttrs as) a), rest)
-                                                        (_,_) ->
-                                                                case (fromElem c0) of
-                                                                (Just a,_) -> (Just (PlistTrue (fromAttrs as) a), rest)
-                                                                (_,_) ->
-                                                                        case (fromElem c0) of
-                                                                        (Just a,_) -> (Just (PlistFalse (fromAttrs as) a), rest)
-                                                                        (_,_) ->
-                                                                            (Nothing, c0)
-    fromElem (CMisc _:rest) = fromElem rest
-    fromElem (CString _ s:rest) | all isSpace s = fromElem rest
-    fromElem rest = (Nothing, rest)
-    toElem (PlistArray as a) = [CElem (Elem "plist" (toAttrs as) (toElem a) )]
-    toElem (PlistData as a) = [CElem (Elem "plist" (toAttrs as) (toElem a) )]
-    toElem (PlistDate as a) = [CElem (Elem "plist" (toAttrs as) (toElem a) )]
-    toElem (PlistDict as a) = [CElem (Elem "plist" (toAttrs as) (toElem a) )]
-    toElem (PlistAReal as a) = [CElem (Elem "plist" (toAttrs as) (toElem a) )]
-    toElem (PlistAInteger as a) = [CElem (Elem "plist" (toAttrs as) (toElem a) )]
-    toElem (PlistAString as a) = [CElem (Elem "plist" (toAttrs as) (toElem a) )]
-    toElem (PlistTrue as a) = [CElem (Elem "plist" (toAttrs as) (toElem a) )]
-    toElem (PlistFalse as a) = [CElem (Elem "plist" (toAttrs as) (toElem a) )]
-instance XmlAttributes Plist_Attrs where
-    fromAttrs as =
-        Plist_Attrs
-          { plistVersion = defaultA fromAttrToStr "1.0" "version" as
-          }
-    toAttrs v = catMaybes 
-        [ defaultToAttr toAttrFrStr "version" (plistVersion v)
-        ]
-instance XmlContent Array where
-    fromElem (CElem (Elem "array" [] c0):rest) =
-        (\(a,ca)->
-           (Just (Array a), rest))
-        (many fromElem c0)
-    fromElem (CMisc _:rest) = fromElem rest
-    fromElem (CString _ s:rest) | all isSpace s = fromElem rest
-    fromElem rest = (Nothing, rest)
-    toElem (Array a) =
-        [CElem (Elem "array" [] (concatMap toElem a))]
-instance XmlContent Dict where
-    fromElem (CElem (Elem "dict" [] c0):rest) =
-        (\(a,ca)->
-           (Just (Dict a), rest))
-        (many fromElem c0)
-    fromElem (CMisc _:rest) = fromElem rest
-    fromElem (CString _ s:rest) | all isSpace s = fromElem rest
-    fromElem rest = (Nothing, rest)
-    toElem (Dict a) =
-        [CElem (Elem "dict" [] (concatMap toElem a))]
-instance XmlContent Dict_ where
-    fromElem c0 =
-        case (\(a,ca)->
-                (\(b,cb)->
-                   (a,b,cb))
-                (fromElem ca))
-             (fromElem c0) of
-        (Just a,Just b,rest) -> (Just (Dict_ a b), rest)
-        (_,_,_) ->
-            (Nothing, c0)
-    toElem (Dict_ a b) =
-        (toElem a ++ toElem b)
-instance XmlContent Key where
-    fromElem (CElem (Elem "key" [] c0):rest) =
-        (\(a,ca)->
-           (Just (Key a), rest))
-        (definite fromText "text" "key" c0)
-    fromElem (CMisc _:rest) = fromElem rest
-    fromElem (CString _ s:rest) | all isSpace s = fromElem rest
-    fromElem rest = (Nothing, rest)
-    toElem (Key a) =
-        [CElem (Elem "key" [] (toText a))]
-instance XmlContent AString where
-    fromElem (CElem (Elem "string" [] c0):rest) =
-        (\(a,ca)->
-           (Just (AString a), rest))
-        (definite fromText "text" "string" c0)
-    fromElem (CMisc _:rest) = fromElem rest
-    fromElem (CString _ s:rest) | all isSpace s = fromElem rest
-    fromElem rest = (Nothing, rest)
-    toElem (AString a) =
-        [CElem (Elem "string" [] (toText a))]
-instance XmlContent Data where
-    fromElem (CElem (Elem "data" [] c0):rest) =
-        (\(a,ca)->
-           (Just (Data a), rest))
-        (definite fromText "text" "data" c0)
-    fromElem (CMisc _:rest) = fromElem rest
-    fromElem (CString _ s:rest) | all isSpace s = fromElem rest
-    fromElem rest = (Nothing, rest)
-    toElem (Data a) =
-        [CElem (Elem "data" [] (toText a))]
-instance XmlContent Date where
-    fromElem (CElem (Elem "date" [] c0):rest) =
-        (\(a,ca)->
-           (Just (Date a), rest))
-        (definite fromText "text" "date" c0)
-    fromElem (CMisc _:rest) = fromElem rest
-    fromElem (CString _ s:rest) | all isSpace s = fromElem rest
-    fromElem rest = (Nothing, rest)
-    toElem (Date a) =
-        [CElem (Elem "date" [] (toText a))]
-instance XmlContent True where
-    fromElem (CElem (Elem "true" [] []):rest) =
-        (Just True, rest)
-    fromElem (CMisc _:rest) = fromElem rest
-    fromElem (CString _ s:rest) | all isSpace s = fromElem rest
-    fromElem rest = (Nothing, rest)
-    toElem True =
-        [CElem (Elem "true" [] [])]
-instance XmlContent False where
-    fromElem (CElem (Elem "false" [] []):rest) =
-        (Just False, rest)
-    fromElem (CMisc _:rest) = fromElem rest
-    fromElem (CString _ s:rest) | all isSpace s = fromElem rest
-    fromElem rest = (Nothing, rest)
-    toElem False =
-        [CElem (Elem "false" [] [])]
-instance XmlContent AReal where
-    fromElem (CElem (Elem "real" [] c0):rest) =
-        (\(a,ca)->
-           (Just (AReal a), rest))
-        (definite fromText "text" "real" c0)
-    fromElem (CMisc _:rest) = fromElem rest
-    fromElem (CString _ s:rest) | all isSpace s = fromElem rest
-    fromElem rest = (Nothing, rest)
-    toElem (AReal a) =
-        [CElem (Elem "real" [] (toText a))]
-instance XmlContent AInteger where
-    fromElem (CElem (Elem "integer" [] c0):rest) =
-        (\(a,ca)->
-           (Just (AInteger a), rest))
-        (definite fromText "text" "integer" c0)
-    fromElem (CMisc _:rest) = fromElem rest
-    fromElem (CString _ s:rest) | all isSpace s = fromElem rest
-    fromElem rest = (Nothing, rest)
-    toElem (AInteger a) =
-        [CElem (Elem "integer" [] (toText a))]
-
-
-{-Done-}
diff --git a/src/Data/PropertyList/Xml/Parse.hs b/src/Data/PropertyList/Xml/Parse.hs
deleted file mode 100644
--- a/src/Data/PropertyList/Xml/Parse.hs
+++ /dev/null
@@ -1,122 +0,0 @@
-{-# LANGUAGE 
-    TemplateHaskell, CPP,
-    MultiParamTypeClasses,
-    FlexibleContexts, FlexibleInstances, TypeSynonymInstances,
-    UndecidableInstances, OverlappingInstances, IncoherentInstances
-  #-}
-
-module Data.PropertyList.Xml.Parse where
-
-import Language.Haskell.TH.Fold
-
-import Prelude as P
-#ifdef HaXml_1_13
-import Data.PropertyList.Xml.Dtd_1_13 as X
-#else
-import Data.PropertyList.Xml.Dtd as X
-#endif
-
-import Data.PropertyList.Algebra
-import Data.PropertyList.Xml.Types
-
-import Data.Copointed
-import Control.Arrow ((+++))
-import Control.Monad.Identity
-import qualified Data.Map as M
-import Data.ByteString as B hiding (map)
-import Data.Time
-import System.Locale
-import Codec.Binary.Base64 as B64
-
-import Text.XML.HaXml.OneOfN
-
--- |A representation of values that were structurally sound in the 
--- property list file but the contents of which couldn't be interpreted
--- as what they claimed to be.  The result of the initial parse phase will
--- typically be a @PartialPropertyList UnparsedPlistItem@, and if
--- the whole plist was parsed properly will contain no actual values 
--- of this type.
-data UnparsedPlistItem
-    = UnparsedData String
-    | UnparsedDate String
-    | UnparsedInt  String
-    | UnparsedReal String
-    deriving (Eq, Ord, Show, Read)
-
-dateFormat :: String
-dateFormat = "%FT%TZ"
-
--- This instance is not efficient, and should really only be used as a convenience
--- to allow direct construction of 'Plist's using the \"smart constructors\"
-instance PListAlgebra f PlistItem => PListAlgebra f Plist where
-    plistAlgebra = plistItemToPlist . plistAlgebra . fmap (fmap plistToPlistItem)
-
-instance (Functor f, Copointed f) => PListAlgebra f PlistItem where
-    {-# SPECIALIZE instance PListAlgebra Identity PlistItem #-}
-    plistAlgebra = foldPropertyListS
-          (\x -> OneOf9 (Array x)
-        ) (\x -> TwoOf9 (Data (encode (unpack x)))
-        ) (\x -> ThreeOf9 (Date (formatTime defaultTimeLocale dateFormat x))
-        ) (\x -> FourOf9 (Dict [Dict_ (Key k) v | (k,v) <- M.toList x])
-        ) (\x -> FiveOf9 (AReal (show x))
-        ) (\x -> SixOf9 (AInteger (show x))
-        ) (\x -> SevenOf9 (AString x)
-        ) (\x -> if x then EightOf9 X.True else NineOf9 X.False
-        ) . copoint
-
-instance PListAlgebra   (Either UnparsedPlistItem) PlistItem where
-    plistAlgebra (Left unparsed) = unparsedPlistItemToPlistItem unparsed
-    plistAlgebra (Right parsed) = plistAlgebra (Identity parsed)
-
-instance PListAlgebra   (Either PlistItem) PlistItem where
-    plistAlgebra (Left unparsed) = unparsed
-    plistAlgebra (Right parsed) = plistAlgebra (Identity parsed)
-
-instance PListCoalgebra (Either UnparsedPlistItem) PlistItem where
-    plistCoalgebra item = case item of
-        OneOf9   (Array x   )   -> accept PLArray x
-        TwoOf9   (Data x    )   -> case decode x of 
-                Just d                  -> accept PLData (pack d)
-                Nothing                 -> reject UnparsedData x
-        ThreeOf9 (Date x    )   -> case parseTime defaultTimeLocale dateFormat x of
-                Just t                  -> accept PLDate t
-                Nothing                 -> reject UnparsedDate x
-        FourOf9  (Dict x    )   -> accept PLDict (M.fromList [ (k, v) | Dict_ (Key k) v <- x])
-        FiveOf9  (AReal x   )   -> tryRead PLReal UnparsedReal x
-        SixOf9   (AInteger x)   -> tryRead PLInt  UnparsedInt x
-        SevenOf9 (AString  x)   -> accept PLString x
-        EightOf9 (X.True    )   -> accept PLBool P.True
-        NineOf9  (X.False   )   -> accept PLBool P.False
-        
-        where
-                accept :: (a -> c) -> a -> Either b c
-                accept con = Right . con
-                
-                reject :: (a -> b) -> a -> Either b c
-                reject con = Left  . con
-                
-                tryRead :: Read a => (a -> c) -> (String -> b) -> String -> Either b c
-                tryRead onGood onBad str =
-                        case reads str of
-                                ((result, ""):_) -> accept onGood result
-                                _                -> reject onBad  str
-
-instance PListCoalgebra (Either PlistItem) PlistItem where
-    plistCoalgebra = (unparsedPlistItemToPlistItem +++ id) . plistCoalgebra
-
-instance PListCoalgebra Maybe PlistItem where
-    plistCoalgebra = either (const Nothing) Just . (plistCoalgebra :: PlistItem -> Either PlistItem (PropertyListS PlistItem))
-
--- This instance is not efficient, and should really only be used as a convenience
--- to allow direct deconstruction of 'Plist's using the \"view deconstructors\"
-instance PListCoalgebra f PlistItem => PListCoalgebra f Plist where
-    plistCoalgebra = fmap (fmap plistItemToPlist) . plistCoalgebra . plistToPlistItem
-
--- |Take the unparsed data from an 'UnparsedPlistItem' and wrap it in
--- the appropriate 'PlistItem' constructor.
-unparsedPlistItemToPlistItem :: UnparsedPlistItem -> PlistItem
-unparsedPlistItemToPlistItem = $(fold ''UnparsedPlistItem)
-        (TwoOf9   . Data    )
-        (ThreeOf9 . Date    )
-        (SixOf9   . AInteger)
-        (FiveOf9  . AReal   )
diff --git a/src/Data/PropertyList/Xml/Types.hs b/src/Data/PropertyList/Xml/Types.hs
deleted file mode 100644
--- a/src/Data/PropertyList/Xml/Types.hs
+++ /dev/null
@@ -1,116 +0,0 @@
-{-# LANGUAGE
-        TemplateHaskell, CPP
-  #-}
-
-module Data.PropertyList.Xml.Types
-    ( Plist, PlistItem
-    , plistItemToPlist, plistToPlistItem
-    , readXmlPlist, showXmlPlist
-    ) where
-
-import Prelude as P
-
-import Text.XML.HaXml.OneOfN
-
-#ifdef HaXml_1_13
-import Data.PropertyList.Xml.Dtd_1_13 as X
-import Text.XML.HaXml.Xml2Haskell hiding (showXml, readXml)
-import qualified Text.XML.HaXml.Xml2Haskell as X2H
-#else
-import Data.PropertyList.Xml.Dtd as X
-import Text.XML.HaXml.XmlContent
-        hiding (showXml, toXml)
-#endif
-
-import Text.PrettyPrint.HughesPJ (render)
-import Text.XML.HaXml.Pretty   (document)
-import Text.XML.HaXml.Types
-
-import Language.Haskell.TH.Fold
-
--- * The 'PlistItem' type: Xml-parser-independent view of an xml plist
--- |'PlistItem' is nearly equivalent to 'Plist' - the difference is that it discards
--- information about where in the tree the item is (a 'Plist' represents the whole
--- XML tree starting from the root).  This is a \"slightly-less-opaque\" type,
--- but still isn't really intended for consumption by end users.
-type PlistItem = OneOf9 Array Data Date Dict AReal AInteger AString X.True X.False
-
--- |Convert a 'Plist' to a 'PlistItem', discarding the root element and any 
--- attributes that element may have had.
-plistToPlistItem :: Plist -> PlistItem
-plistToPlistItem = $(fold ''Plist)
-        (\attr -> OneOf9  )
-        (\attr -> TwoOf9  )
-        (\attr -> ThreeOf9)
-        (\attr -> FourOf9 )
-        (\attr -> FiveOf9 )
-        (\attr -> SixOf9  )
-        (\attr -> SevenOf9)
-        (\attr -> EightOf9)
-        (\attr -> NineOf9 )
-
--- |Convert a 'PlistItem' to a 'Plist', giving it a root element with no 
--- attributes.
-plistItemToPlist :: PlistItem -> Plist
-plistItemToPlist = $(fold ''OneOf9)
-        (PlistArray    attr)
-        (PlistData     attr)
-        (PlistDate     attr)
-        (PlistDict     attr)
-        (PlistAReal    attr)
-        (PlistAInteger attr)
-        (PlistAString  attr)
-        (PlistTrue     attr)
-        (PlistFalse    attr)
-        where attr = fromAttrs []
-
--- * Parsing and rendering XML 'Plist's from/to 'String's
-
-#ifdef HaXml_1_13
-
--- |Try to parse a string as an XML property list.
-readXmlPlist :: String -> Either String Plist
-readXmlPlist xml = case X2H.readXml xml of
-    Nothing     -> Left "readXml: parse failed"
-    Just plist  -> Right plist
-
--- |Render a 'Plist' to a 'String' as an XML property list.
-showXmlPlist :: Plist -> String
-showXmlPlist = X2H.showXml
-
--- |Render a 'Plist' as a 'Document' (HaXml's internal DOM representation, I
--- think)
-toXml :: Plist -> Document
-toXml value =
-    Document (Prolog (Just (XMLDecl "1.0" Nothing Nothing)) [] Nothing [])
-             emptyST
-             ( case (toElem value) of
-                 [CElem e] -> e
-                 )
-             []
-
-#else
-
--- |Try to parse a string as an XML property list.
-readXmlPlist :: String -> Either String Plist
-readXmlPlist = readXml
-
--- |Render a 'Plist' to a 'String' as an XML property list.
-showXmlPlist :: Plist -> String
-showXmlPlist x =
-    case toContents x of
-      [CElem _ _] -> (render . document . toXml) x
-      _ -> ""
-
--- |Render a 'Plist' as a 'Document' (HaXml's internal DOM representation, I
--- think)
-toXml :: Plist -> Document ()
-toXml value =
-    Document (Prolog (Just (XMLDecl "1.0" Nothing Nothing)) [] Nothing [])
-             emptyST
-             ( case (toContents value) of
-                 [CElem e ()] -> e
-                 )
-             []
-
-#endif
