packages feed

hpdft-0.4.7.0: src/PDF/StreamLex.hs

{-# LANGUAGE OverloadedStrings #-}

module PDF.StreamLex
  ( normalizePdfNumber
  , parsePdfNumber
  , parsePdfNumberFromByteString
  , hexPairs
  , isUtf16HighSurrogate
  , isUtf16LowSurrogate
  , surrogatePairToCode
  , unicodeBytesToCodes
  , isSjisLead
  , sjisBytesToCodes
  , jisBytesToCodes
  ) where

import Data.Bits (shiftL)
import Data.Char (chr)
import qualified Data.ByteString.Lazy as BSL
import Numeric (readHex)

normalizePdfNumber :: String -> String
normalizePdfNumber s
  | null s = s
  | head s == '.' = '0' : s
  | length s >= 2 && head s == '-' && s !! 1 == '.' = '-' : '0' : drop 1 s
  | otherwise = s

parsePdfNumber :: String -> Double
parsePdfNumber s
  | null s || s == "-" || s == "+" = 0
  | last s == '.' =
      case reads (normalizePdfNumber s ++ "0") of
        [(n, "")] -> n
        _         -> 0
  | otherwise =
      case reads (normalizePdfNumber s) of
        [(n, "")] -> n
        _         -> 0

parsePdfNumberFromByteString :: BSL.ByteString -> Double
parsePdfNumberFromByteString bs =
  parsePdfNumber (map (chr . fromEnum) (BSL.unpack bs))

hexPairs :: String -> [Int]
hexPairs [] = []
hexPairs [x] =
  case readHex [x, '0'] of
    [(n, "")] -> [n]
    _         -> []
hexPairs (a:b:rest) =
  case readHex [a, b] of
    [(n, "")] -> n : hexPairs rest
    _         -> hexPairs rest

isUtf16HighSurrogate :: Int -> Bool
isUtf16HighSurrogate u = u >= 0xD800 && u <= 0xDBFF

isUtf16LowSurrogate :: Int -> Bool
isUtf16LowSurrogate u = u >= 0xDC00 && u <= 0xDFFF

surrogatePairToCode :: Int -> Int -> Int
surrogatePairToCode hi lo = 0x10000 + ((hi - 0xD800) `shiftL` 10) + (lo - 0xDC00)

unicodeBytesToCodes :: [Int] -> [Int]
unicodeBytesToCodes [] = []
unicodeBytesToCodes [_] = []
unicodeBytesToCodes (a:b:rest) =
  let unit = a * 256 + b
  in if isUtf16HighSurrogate unit
     then case rest of
       (c:d:rs) ->
         let unit2 = c * 256 + d
         in if isUtf16LowSurrogate unit2
            then surrogatePairToCode unit unit2 : unicodeBytesToCodes rs
            else unit : unicodeBytesToCodes rest
       _ -> [unit]
     else unit : unicodeBytesToCodes rest

isSjisLead :: Int -> Bool
isSjisLead b = (b >= 0x81 && b <= 0x9F) || (b >= 0xE0 && b <= 0xFC)

sjisBytesToCodes :: [Int] -> [Int]
sjisBytesToCodes [] = []
sjisBytesToCodes (b:rest)
  | isSjisLead b = case rest of
      (t:rs) -> (b * 256 + t) : sjisBytesToCodes rs
      _ -> [b]
  | otherwise = b : sjisBytesToCodes rest

jisBytesToCodes :: [Int] -> [Int]
jisBytesToCodes [] = []
jisBytesToCodes [_] = []
jisBytesToCodes (a:b:rest) = (a * 256 + b) : jisBytesToCodes rest