diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,7 @@
+0.0.3.2
+
+* support array ranges in unicode cmap (#15)
+* support Op\_apostrophe content operator (#16)
 
 0.0.3.1
 
diff --git a/lib/Pdf/Toolbox/Content/Processor.hs b/lib/Pdf/Toolbox/Content/Processor.hs
--- a/lib/Pdf/Toolbox/Content/Processor.hs
+++ b/lib/Pdf/Toolbox/Content/Processor.hs
@@ -269,6 +269,11 @@
     }
 processOp (Op_Tw, args) _ = left $ UnexpectedError $ "Op_Tw: wrong number of agruments:" ++ show args
 
+processOp (Op_apostrophe, [o]) p = do
+  p' <- processOp (Op_T_star, []) p
+  processOp (Op_Tj, [o]) p'
+processOp (Op_apostrophe, args) _ = left $ UnexpectedError $ "Op_apostrophe: wrong number of agruments:" ++ show args
+
 processOp _ p = return p
 
 ensureInTextObject :: Monad m => Bool -> Processor -> PdfE m ()
diff --git a/lib/Pdf/Toolbox/Content/UnicodeCMap.hs b/lib/Pdf/Toolbox/Content/UnicodeCMap.hs
--- a/lib/Pdf/Toolbox/Content/UnicodeCMap.hs
+++ b/lib/Pdf/Toolbox/Content/UnicodeCMap.hs
@@ -11,6 +11,8 @@
 )
 where
 
+import Data.Monoid
+import Data.Functor
 import Data.Char
 import Data.Map (Map)
 import qualified Data.Map as Map
@@ -39,9 +41,9 @@
 parseUnicodeCMap :: ByteString -> Either String UnicodeCMap
 parseUnicodeCMap cmap =
   case (codeRanges, chars, ranges) of
-    (Right cr, Right cs, Right rs) -> Right $ UnicodeCMap {
+    (Right cr, Right cs, Right (rs, crs)) -> Right $ UnicodeCMap {
       unicodeCMapCodeRanges = cr,
-      unicodeCMapChars = cs,
+      unicodeCMapChars = cs <> crs,
       unicodeCMapRanges = rs
       }
     (Left err, _, _) -> Left $ "CMap code ranges: " ++ err
@@ -67,7 +69,9 @@
   inRange glyph (start, end) = glyph >= start && glyph <= end
 
 toCode :: ByteString -> Int
-toCode bs = fst $ BS.foldr (\b (sm, i) -> (sm + fromIntegral b * i, i * 255)) (0, 1) bs
+toCode bs = fst $ BS.foldr (\b (sm, i) ->
+                    (sm + fromIntegral b * i, i * 255)) (0, 1) bs
+
 -- | Convert glyph to text
 --
 -- Note: one glyph can represent more then one char, e.g. for ligatures
@@ -77,7 +81,8 @@
     Just txt -> Just txt
     Nothing ->
       case filter inRange (unicodeCMapRanges cmap) of
-        [(start, _, char)] -> Just (Text.singleton $ toEnum $ (fromEnum char) + (glyph - start))
+        [(start, _, char)] -> Just (Text.singleton $ toEnum
+                                    $ (fromEnum char) + (glyph - start))
         _ -> Nothing
   where
   inRange (start, end, _) = glyph >= start && glyph <= end
@@ -92,59 +97,77 @@
 
   chars <- replicateM n $ do
     P.skipSpace
-    _ <- P.char '<'
-    i <- P.takeTill (== '>') >>= fromHex
-    _ <- P.char '>'
+    i <- parseHex
     P.skipSpace
-    _ <- P.char '<'
-    j <- P.takeTill (== '>') >>= fromHex
-    _ <- P.char '>'
+    j <- parseHex
     return (toCode i, Text.decodeUtf16BE j)
 
   return $ Map.fromList chars
 
-rangesParser :: Parser [(Int, Int, Char)]
+-- | It returns regular ranges and char map
+--
+-- Array ranges are converted to char map
+rangesParser :: Parser ([(Int, Int, Char)], Map Int Text)
 rangesParser = do
-  n <- P.option 0 $ skipTillParser $ do
+  n <- P.option (0 :: Int) $ skipTillParser $ do
     n <- P.decimal
     P.skipSpace
-    _ <- P.string "beginbfrange"
+    void $ P.string "beginbfrange"
     return n
 
-  replicateM n $ do
-    P.skipSpace
-    _ <- P.char '<'
-    i <- P.takeTill (== '>') >>= fromHex
-    _ <- P.char '>'
-    P.skipSpace
-    _ <- P.char '<'
-    j <- P.takeTill (== '>') >>= fromHex
-    _ <- P.char '>'
-    P.skipSpace
-    _ <- P.char '<'
-    k <- P.takeTill (== '>') >>= fromHex
-    _ <- P.char '>'
-    return (toCode i, toCode j, Text.head $ Text.decodeUtf16BE k)
+  let go 0 rs cs = return (rs, cs)
+      go count rs cs = do
+        P.skipSpace
+        i <- toCode <$> parseHex
+        P.skipSpace
+        j <- toCode <$> parseHex
+        P.skipSpace
+        k <- P.eitherP parseHex parseHexArray
+        case k of
+          Left h -> do
+            c <- case Text.uncons $ Text.decodeUtf16BE h of
+                   Nothing -> fail "Can't decode range"
+                   Just (v, _) -> return v
+            go (pred count) ((i, j, c) : rs) cs
+          Right hs -> do
+            let cs' = zip [i..j] . map Text.decodeUtf16BE $ hs
+            go (pred count) rs (cs <> Map.fromList cs')
 
+  go n mempty mempty
+
 codeRangesParser :: Parser [(ByteString, ByteString)]
 codeRangesParser = do
   n <- skipTillParser $ do
     n <- P.decimal
     P.skipSpace
-    _ <- P.string "begincodespacerange"
+    void $ P.string "begincodespacerange"
     return n
 
   replicateM n $ do
     P.skipSpace
-    _ <- P.char '<'
-    i <- P.takeTill (== '>') >>= fromHex
-    _ <- P.char '>'
+    i <- parseHex
     P.skipSpace
-    _ <- P.char '<'
-    j <- P.takeTill (== '>') >>= fromHex
-    _ <- P.char '>'
+    j <- parseHex
     return (i, j)
 
+parseHex :: Parser ByteString
+parseHex = do
+  void $ P.char '<'
+  res <- P.takeTill (== '>') >>= fromHex
+  void $ P.char '>'
+  return res
+
+parseHexArray :: Parser [ByteString]
+parseHexArray = do
+  void $ P.char '['
+  res <- P.many' $ do
+    P.skipSpace
+    parseHex
+  P.skipSpace
+  void $ P.char ']'
+  return res
+
+-- XXX: wtf?!
 fromHex :: Monad m => ByteString -> m ByteString
 fromHex hex = do
   let (str, rest) = Base16.decode $ bsToLower hex
@@ -152,7 +175,11 @@
     fail $ "Can't decode hex" ++ show rest
   return str
   where
-  bsToLower = BS.map $ fromIntegral . fromEnum . toLower . toEnum . fromIntegral
+  bsToLower = BS.map $ fromIntegral
+                     . fromEnum
+                     . toLower
+                     . toEnum
+                     . fromIntegral
 
 skipTillParser :: Parser a -> Parser a
 skipTillParser p = P.choice [
diff --git a/pdf-toolbox-content.cabal b/pdf-toolbox-content.cabal
--- a/pdf-toolbox-content.cabal
+++ b/pdf-toolbox-content.cabal
@@ -1,11 +1,11 @@
 name:                pdf-toolbox-content
-version:             0.0.3.1
+version:             0.0.3.2
 synopsis:            A collection of tools for processing PDF files
 license:             BSD3
 license-file:        LICENSE
 author:              Yuras Shumovich
 maintainer:          Yuras Shumovich <shumovichy@gmail.com>
-copyright:           Copyright (c) Yuras Shumovich 2013-2014
+copyright:           Copyright (c) Yuras Shumovich 2013-2015
 category:            PDF
 build-type:          Simple
 cabal-version:       >=1.8
