summaryrefslogtreecommitdiff
path: root/app/Main.hs
blob: aee0fd42dc8821664fb0fca3ff07ab8582c0eab9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
module Main
    ( main
    ) where

import Control.Monad (foldM_)
import Data.Int (Int64)
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Char8 as Char8
import Data.ByteString (ByteString)
import qualified Text.Megaparsec as Megaparsec
import Data.Foldable (find)
import qualified Data.Text.Lazy.Builder as Text.Builder
import qualified Data.Text.Lazy.Builder.Int as Text.Builder
import qualified Data.Text.Lazy as Text.Lazy
import qualified Data.Text.Lazy.IO as Text.Lazy
import qualified Data.Text.Encoding as Text
import GHC.Records (HasField(..))
-- TODO: kern table since format 1.
-- For details on subtable format see examples in TrueType reference.
import Graphics.Fountainhead.Parser
    ( fontDirectoryP
    , os2TableP
    , parseTable
    , shortLocaTableP
    )
import Graphics.Fountainhead.TrueType
    ( FontDirectory(..)
    , OffsetSubtable(..)
    , TableDirectory(..)
    )
import System.Environment (getArgs)
import System.Exit (exitWith)
import GHC.IO.Exception (ExitCode(..))

fontMain :: FilePath -> IO ()
fontMain fontFile = do
    putStrLn $ "Dumping File:" <> fontFile <> "\n\n"

    ttfContents <- ByteString.readFile fontFile

    let initialState = Megaparsec.State
            { stateInput = ttfContents
            , stateOffset = 0
            , statePosState = Megaparsec.PosState
                { pstateInput = ttfContents
                , pstateOffset = 0
                , pstateSourcePos = Megaparsec.initialPos fontFile
                , pstateTabWidth = Megaparsec.defaultTabWidth
                , pstateLinePrefix = ""
                }
            , stateParseErrors = []
            }
        (processedState, Right directory) = Megaparsec.runParser' fontDirectoryP initialState

    Text.Lazy.putStrLn $ Text.Builder.toLazyText $ dumpOffsetTable directory
    {- print directory
    let Just tableDirectory' = find (("OS/2" ==) . tag) $ tableDirectory directory
        tableResult = parseTable tableDirectory' os2TableP processedState
    case tableResult of
        Left e -> putStr (Megaparsec.errorBundlePretty e)
        Right x -> print x -}

paddedHexadecimal :: Integral a => a -> Text.Builder.Builder
paddedHexadecimal = ("0x" <>)
    . Text.Builder.fromLazyText
    . Text.Lazy.justifyRight 8 '0'
    . Text.Builder.toLazyText
    . Text.Builder.hexadecimal

justifyNumber :: Integral a => Int64 -> a -> Text.Builder.Builder
justifyNumber count = Text.Builder.fromLazyText
    . Text.Lazy.justifyRight count ' '
    . Text.Builder.toLazyText
    . Text.Builder.decimal

dumpOffsetTable :: FontDirectory -> Text.Builder.Builder
dumpOffsetTable directory
    = "Offset Table\n------------\n"
    <> "         sfnt version:           1.0\n         number of tables: "
    <> Text.Builder.decimal (numTables $ offsetSubtable directory)
    <> Text.Builder.singleton '\n'
    <> dumpOffsetSummary (tableDirectory directory)
  where
    dumpOffsetSummary = mconcat . fmap dumpOffsetRow . zip [0..]
    dumpOffsetRow (index, table) = justifyNumber 4 index
        <> ". '"
        <> Text.Builder.fromText (Text.decodeASCII $ tag table)
        <> "' - checksum = "
        <> paddedHexadecimal (getField @"checkSum" table)
        <> ", offset = "
        <> paddedHexadecimal (getField @"offset" table)
        <> ", len = "
        <> justifyNumber 9 (getField @"length" table)
        <> Text.Builder.singleton '\n'

main :: IO ()
main = do
    programArguments <- getArgs
    case programArguments of
        [fontFile] -> fontMain fontFile
        _ -> putStrLn "The program expects exactly one argument, the font file path."
            >> exitWith (ExitFailure 2)