{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE PatternGuards #-}
module Text.Pandoc.Readers.Odt ( readOdt ) where
import Prelude
import Codec.Archive.Zip
import qualified Text.XML.Light as XML
import qualified Data.ByteString.Lazy as B
import System.FilePath
import Control.Monad.Except (throwError)
import Text.Pandoc.Class (PandocMonad)
import qualified Text.Pandoc.Class as P
import Text.Pandoc.Definition
import Text.Pandoc.Error
import Text.Pandoc.MediaBag
import Text.Pandoc.Options
import qualified Text.Pandoc.UTF8 as UTF8
import Text.Pandoc.Readers.Odt.ContentReader
import Text.Pandoc.Readers.Odt.StyleReader
import Text.Pandoc.Readers.Odt.Generic.Fallible
import Text.Pandoc.Readers.Odt.Generic.XMLConverter
import Text.Pandoc.Shared (filteredFilesFromArchive)
readOdt :: PandocMonad m
=> ReaderOptions
-> B.ByteString
-> m Pandoc
readOdt opts bytes = case readOdt' opts bytes of
Right (doc, mb) -> do
P.setMediaBag mb
return doc
Left e -> throwError e
readOdt' :: ReaderOptions
-> B.ByteString
-> Either PandocError (Pandoc, MediaBag)
readOdt' _ bytes = bytesToOdt bytes
bytesToOdt :: B.ByteString -> Either PandocError (Pandoc, MediaBag)
bytesToOdt bytes = case toArchiveOrFail bytes of
Right archive -> archiveToOdt archive
Left _ -> Left $ PandocParseError "Couldn't parse odt file."
archiveToOdt :: Archive -> Either PandocError (Pandoc, MediaBag)
archiveToOdt archive
| Just contentEntry <- findEntryByPath "content.xml" archive
, Just stylesEntry <- findEntryByPath "styles.xml" archive
, Just contentElem <- entryToXmlElem contentEntry
, Just stylesElem <- entryToXmlElem stylesEntry
, Right styles <- chooseMax (readStylesAt stylesElem )
(readStylesAt contentElem)
, media <- filteredFilesFromArchive archive filePathIsOdtMedia
, startState <- readerState styles media
, Right pandocWithMedia <- runConverter' read_body
startState
contentElem
= Right pandocWithMedia
| otherwise
= Left $ PandocParseError "Couldn't parse odt file."
where
filePathIsOdtMedia :: FilePath -> Bool
filePathIsOdtMedia fp =
let (dir, _) = splitFileName fp
in
(dir == "Pictures/")
entryToXmlElem :: Entry -> Maybe XML.Element
entryToXmlElem = XML.parseXMLDoc . UTF8.toStringLazy . fromEntry