Sophie

Sophie

distrib > Mageia > 4 > x86_64 > by-pkgid > 199168df3fabe584b2d6b1a05ca44868 > files > 30

ocaml-otfm-devel-0.1.0-2.mga4.x86_64.rpm

(*---------------------------------------------------------------------------
   Copyright 2013 Daniel C. Bünzli. All rights reserved.
   Distributed under the BSD3 license, see license at the end of the file.
   otfm release 0.1.0
  ---------------------------------------------------------------------------*)

let pp = Format.fprintf 
let str = Format.sprintf

let exec = Filename.basename Sys.executable_name 
let log msg = Format.eprintf ("%s: " ^^ msg ^^ "@.") exec
let log_err inf e = 
  Format.eprintf "@[<2>%s:%s:@ %a@]@." exec inf Otfm.pp_error e

let string_of_file inf =
  try
    let ic = if inf = "-" then stdin else open_in_bin inf in
    let close ic = if inf <> "-" then close_in ic else () in
    let buf_size = 65536 in
    let b = Buffer.create buf_size in 
    let s = String.create buf_size in 
    try
      while true do
        let c = input ic s 0 buf_size in 
        if c = 0 then raise Exit else
        Buffer.add_substring b s 0 c
      done;
      assert false
    with
    | Exit -> close ic; `Ok (Buffer.contents b)
    | Failure _ -> close ic; `Error (`Msg (str "%s: input file too large" inf))
    | Sys_error e -> close ic; (`Error (`Msg e));
  with
  | Sys_error e -> (`Error (`Msg e))

(* Table pretty printers *)     
               
let pp_cmap ppf d =
  let pp_map ppf u gid = pp ppf "@,(%a %d)" Uutf.pp_cp u gid in
  let pp_binding ppf () k (u0, u1) gid = match k with 
  | `Glyph -> for u = u0 to u1 do pp_map ppf u gid done
  | `Glyph_range -> for i = 0 to (u1 - u0) do pp_map ppf (u0 + i) (gid + i)done 
  in
  pp ppf "@,@[<v1>(cmap";
  match Otfm.cmap d (pp_binding ppf) () with
  | `Error _ as e -> e
  | `Ok ((pid, eid, fmt), _) ->
      pp ppf "@,@[<1>(source@ (platform-id %d)@ (encoding-id %d)\
              @ (format %d))@])@]" pid eid fmt; 
      `Ok ()
        
let pp_head ppf d = 
  pp ppf "@,@[<v1>(head"; 
  match Otfm.head d with 
  | `Error _ as e -> e
  | `Ok h ->
      pp ppf "@,(font-revision 0x%08lX)" h.Otfm.head_font_revision; 
      pp ppf "@,(flags 0x%04X)" h.Otfm.head_flags; 
      pp ppf "@,(units-per-em %d)" h.Otfm.head_units_per_em; 
      pp ppf "@,(created %f)" h.Otfm.head_created; 
      pp ppf "@,(modified %f)" h.Otfm.head_modified; 
      pp ppf "@,(xmin %d)" h.Otfm.head_xmin;
      pp ppf "@,(ymin %d)" h.Otfm.head_ymin;
      pp ppf "@,(xmax %d)" h.Otfm.head_xmax;
      pp ppf "@,(ymax %d)" h.Otfm.head_ymax;
      pp ppf "@,(mac-style 0x%04X)" h.Otfm.head_mac_style;
      pp ppf "@,(lowest_rec_ppem %d)" h.Otfm.head_lowest_rec_ppem;
      pp ppf "@,(index_to_loc_format %d)" h.Otfm.head_index_to_loc_format;
      pp ppf ")@]"; 
      `Ok ()

let pp_hhea ppf d = match Otfm.hhea d with 
| `Error _ as e -> e
| `Ok h ->
    pp ppf "@,@[<v1>(hhea"; 
    pp ppf "@,(ascender %d)" h.Otfm.hhea_ascender; 
    pp ppf "@,(descender %d)" h.Otfm.hhea_descender; 
    pp ppf "@,(line-gap %d)" h.Otfm.hhea_line_gap; 
    pp ppf "@,(advance-width-max %d)" h.Otfm.hhea_advance_width_max; 
    pp ppf "@,(min-left-side-bearing %d)" h.Otfm.hhea_min_left_side_bearing; 
    pp ppf "@,(min-right-side-bearing %d)" h.Otfm.hhea_min_right_side_bearing;
    pp ppf "@,(xmax-extent %d)" h.Otfm.hhea_xmax_extent; 
    pp ppf "@,(caret-slope-rise %d)" h.Otfm.hhea_caret_slope_rise; 
    pp ppf "@,(caret-slope-run %d)" h.Otfm.hhea_caret_slope_run; 
    pp ppf "@,(caret-offset %d)" h.Otfm.hhea_caret_offset;
    pp ppf ")@]"; 
    `Ok ()

let pp_hmtx ppf d = 
  let pp_hm ppf () id adv lsb = pp ppf "@,(%d (adv %d) (lsb %d))" id adv lsb in
  pp ppf "@,@[<v1>(hmtx";
  match Otfm.hmtx d (pp_hm ppf) () with 
  | `Error _ as e -> e
  | `Ok () -> pp ppf ")@]"; `Ok ()
  
let pp_name ppf d = 
  let pp_n ppf () id lang string = pp ppf "@,(%d %s \"%s\")" id lang string in
  pp ppf "@,@[<v1>(name"; 
  match Otfm.name d (pp_n ppf) () with 
  | `Error _ as e -> e
  | `Ok () -> pp ppf ")@]"; `Ok ()

let pp_os2 ppf d = 
  let pp_opt pp_v ppf = function None -> pp ppf "None" | Some v -> pp_v ppf v in
  let pp_ouint32 ppf v = pp_opt (fun ppf v -> pp ppf "%lX" v) ppf v in
  let pp_oint = pp_opt Format.pp_print_int in
  match Otfm.os2 d with
  | `Error _ as e -> e
  | `Ok o ->
      pp ppf "@,@[<v1>(os2"; 
      pp ppf "@,(x-avg-char-width %d)" o.Otfm.os2_x_avg_char_width;
      pp ppf "@,(us-weight-class %d)" o.Otfm.os2_us_weight_class;
      pp ppf "@,(us-width-class %d)" o.Otfm.os2_us_width_class;
      pp ppf "@,(fs-type %X)" o.Otfm.os2_fs_type;
      pp ppf "@,(y-subscript-x-size %d)" o.Otfm.os2_y_subscript_x_size;
      pp ppf "@,(y-subscript-y-size %d)" o.Otfm.os2_y_subscript_y_size;
      pp ppf "@,(y-subscript-x-offset %d)" o.Otfm.os2_y_subscript_x_offset;
      pp ppf "@,(y-subscript-y-offset %d)" o.Otfm.os2_y_subscript_y_offset;
      pp ppf "@,(y-superscript-x-size %d)" o.Otfm.os2_y_superscript_x_size;
      pp ppf "@,(y-superscript-y-size %d)" o.Otfm.os2_y_superscript_y_size;
      pp ppf "@,(y-superscript-x-offset %d)" o.Otfm.os2_y_superscript_x_offset;
      pp ppf "@,(y-superscript-y-offset %d)" o.Otfm.os2_y_superscript_y_offset;
      pp ppf "@,(y-strikeout-size %d)" o.Otfm.os2_y_strikeout_size;
      pp ppf "@,(y-strikeout-position %d)" o.Otfm.os2_y_strikeout_position;
      pp ppf "@,(family-class %d)" o.Otfm.os2_family_class;
      pp ppf "@,(panose \"%s\")" (String.escaped o.Otfm.os2_panose);
      pp ppf "@,(ul-unicode-range1 %lX)" o.Otfm.os2_ul_unicode_range1;
      pp ppf "@,(ul-unicode-range2 %lX)" o.Otfm.os2_ul_unicode_range2;
      pp ppf "@,(ul-unicode-range3 %lX)" o.Otfm.os2_ul_unicode_range3;
      pp ppf "@,(ul-unicode-range4 %lX)" o.Otfm.os2_ul_unicode_range4;
      pp ppf "@,(ach-vend-id %a)" 
        Otfm.Tag.pp (Otfm.Tag.of_int32 o.Otfm.os2_ach_vend_id);
      pp ppf "@,(fs-selection %X)" o.Otfm.os2_fs_selection;
      pp ppf "@,(us-first-char-index %d)" o.Otfm.os2_us_first_char_index;
      pp ppf "@,(us-last-char-index %d)" o.Otfm.os2_us_last_char_index;
      pp ppf "@,(s-typo-ascender %d)" o.Otfm.os2_s_typo_ascender;
      pp ppf "@,(s-type-descender %d)" o.Otfm.os2_s_type_descender;
      pp ppf "@,(s-typo-linegap %d)" o.Otfm.os2_s_typo_linegap;
      pp ppf "@,(us-win-ascent %d)" o.Otfm.os2_us_win_ascent;
      pp ppf "@,(us-win-descent %d)" o.Otfm.os2_us_win_descent;
      pp ppf "@,(ul-code-page-range-1 %a)" 
        pp_ouint32 o.Otfm.os2_ul_code_page_range_1;
      pp ppf "@,(ul-code-page-range-2 %a)" 
        pp_ouint32 o.Otfm.os2_ul_code_page_range_2;
      pp ppf "@,(s-x-height %a)" pp_oint o.Otfm.os2_s_x_height;
      pp ppf "@,(s-cap-height %a)" pp_oint o.Otfm.os2_s_cap_height;
      pp ppf "@,(us-default-char %a)" pp_oint o.Otfm.os2_us_default_char;
      pp ppf "@,(us-break-char %a)" pp_oint o.Otfm.os2_us_break_char;
      pp ppf "@,(us-max-context %a)" pp_oint o.Otfm.os2_us_max_context;
      pp ppf ")@]"; 
      `Ok ()

let pp_kern ppf has_kern d =
  if not has_kern then `Ok () else
  let dir = function `H -> "H" | `V -> "V" in 
  let kind = function `Kern -> "kerning" | `Min -> "minimal" in
  let pp_kinfo ppf first i = 
    if not first then pp ppf ")@]";
    pp ppf "@,@[<v1>((dir %s)@,(kind %s)@,(cross-stream %b)" 
      (dir i.Otfm.kern_dir) (kind i.Otfm.kern_kind) 
      (i.Otfm.kern_cross_stream); 
    `Fold, false
  in
  let pp_pair ppf first l r v = pp ppf "@,(%d %d %d)" l r v; first in
  pp ppf "@,@[<v1>(kern";
  match Otfm.kern d (pp_kinfo ppf) (pp_pair ppf) true with
  | `Error _ as e -> e
  | `Ok _ -> pp ppf ")@])@]"; `Ok ()
  
let pp_tables ppf inf ts d =
  let err = ref false in
  let ( >>= ) x f = match x with 
  | `Ok () -> f ()
  | `Error e -> log_err inf e; err := true; f ()
  in
  pp_name ppf d >>= fun () ->
  pp_head ppf d >>= fun () ->
  pp_hhea ppf d >>= fun () ->
  pp_os2  ppf d >>= fun () ->
  pp_cmap ppf d >>= fun () ->
  pp_hmtx ppf d >>= fun () ->
  pp_kern ppf (List.mem Otfm.Tag.kern ts) d >>= fun () ->
  if !err then (`Error `Reported) else `Ok ()
                           
(* Commands *) 
                           
let pp_file ppf inf = match string_of_file inf with
| `Error _ as e -> e
| `Ok s ->
    let ( >>= ) x f = match x with 
    | `Ok v -> f v 
    | `Error e -> `Error (e :> [ Otfm.error | `Reported | `Msg of string])
    in
    let d = Otfm.decoder (`String s) in
    Otfm.flavour d >>= fun f -> 
    pp ppf "@[<v1>(@[<1>(file %S)@]" inf;
    let fs = match f with `TTF -> "TTF" | `CFF -> "CFF" in
    pp ppf "@,@[<1>(flavor %s)@]" fs;
    Otfm.postscript_name d >>= fun name -> 
    let oname = match name with None -> "<none>" | Some n -> n in
    pp ppf "@,@[<1>(postscript-name %s)@]" oname; 
    Otfm.glyph_count d >>= fun glyph_count -> 
    pp ppf "@,@[<1>(glyph-count %d)@]" glyph_count;
    Otfm.table_list d >>= fun ts -> 
    pp ppf "@,@[<1>(tables ";
    List.iter (fun t -> pp ppf "@ %a" Otfm.Tag.pp t) ts; 
    pp ppf ")@]";
    pp_tables ppf inf ts d >>= fun () -> 
    pp ppf ")@]@."; 
    `Ok ()
      
let dec_file inf = match string_of_file inf with 
| `Error _ as e -> e
| `Ok s -> 
    let err = ref false in
    let ( >>= ) x f = match x with 
    | `Ok _ -> f () 
    | `Error e -> log_err inf e; err := true; f ()
    in 
    let kern_nop () _ = `Fold, () in
    let nop4 _ _ _ _ = () in
    let d = Otfm.decoder (`String s) in
    Otfm.flavour d      >>= fun () -> 
    Otfm.table_list d   >>= fun () ->
    Otfm.cmap d nop4 () >>= fun () -> 
    Otfm.head d         >>= fun () -> 
    Otfm.hhea d         >>= fun () -> 
    Otfm.hmtx d nop4 () >>= fun () -> 
    Otfm.name d nop4 () >>= fun () ->
    Otfm.os2  d         >>= fun () -> 
    Otfm.kern d kern_nop nop4 () >>= fun () ->
    if !err then (`Error `Reported) else `Ok ()
        
let ps_file inf = match string_of_file inf with
| `Error _ as e -> e
| `Ok s -> 
    let d = Otfm.decoder (`String s) in 
    match Otfm.postscript_name d with 
    | `Error e -> `Error (e :> [ Otfm.error | `Reported | `Msg of string])
    | `Ok None -> Printf.printf "%s: <none>\n" inf; `Ok ()
    | `Ok (Some n) -> Printf.printf "%s: %s\n" inf n; `Ok ()

(* otftrip *)

let main () = 
  let usage = Printf.sprintf 
    "Usage: %s [OPTION]... [OTFFILE]...\n\
     Print human readable OpenType file font information on stdout.\n\
    Options:" exec 
  in
  let cmd = ref `Pp in 
  let set_cmd v () = cmd := v in
  let files = ref [] in 
  let add_file f = files := f :: !files in
  let options = [
    "-d", Arg.Unit (set_cmd `Dec), "Decode only";
    "-p", Arg.Unit (set_cmd `Ps), "Only output postscript name"; 
  ]
  in
  Arg.parse (Arg.align options) add_file usage; 
  let files = match List.rev ! files with [] -> ["-"] | fs -> fs in
  let cmd = match !cmd with
  | `Pp -> pp_file Format.std_formatter
  | `Dec -> dec_file
  | `Ps -> ps_file
  in
  let fold_cmd cmd err fn = match cmd fn with 
  | `Error `Reported -> true 
  | `Error (`Msg e) -> log "%s" e; true 
  | `Error (#Otfm.error as e) -> log_err fn e; true
  | `Ok () -> err
  in
  let err = List.fold_left (fold_cmd cmd) false files in 
  if err then exit 1 else exit 0 

let () = main ()

(*---------------------------------------------------------------------------
   Copyright 2013 Daniel C. Bünzli.
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:
     
   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

   3. Neither the name of Daniel C. Bünzli nor the names of
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  ---------------------------------------------------------------------------*)