| /* | |
| * Copyright © 2018 Adobe Inc. | |
| * | |
| * This is part of HarfBuzz, a text shaping library. | |
| * | |
| * Permission is hereby granted, without written agreement and without | |
| * license or royalty fees, to use, copy, modify, and distribute this | |
| * software and its documentation for any purpose, provided that the | |
| * above copyright notice and the following two paragraphs appear in | |
| * all copies of this software. | |
| * | |
| * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | |
| * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | |
| * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | |
| * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |
| * DAMAGE. | |
| * | |
| * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | |
| * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | |
| * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | |
| * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | |
| * | |
| * Adobe Author(s): Michiharu Ariza | |
| */ | |
| #ifndef HB_CFF_INTERP_DICT_COMMON_HH | |
| #define HB_CFF_INTERP_DICT_COMMON_HH | |
| #include "hb-cff-interp-common.hh" | |
| namespace CFF { | |
| using namespace OT; | |
| /* an opstr and the parsed out dict value(s) */ | |
| struct dict_val_t : op_str_t | |
| { | |
| void init () {} | |
| void fini () {} | |
| }; | |
| typedef dict_val_t num_dict_val_t; | |
| template <typename VAL> struct dict_values_t : parsed_values_t<VAL> {}; | |
| template <typename OPSTR=op_str_t> | |
| struct top_dict_values_t : dict_values_t<OPSTR> | |
| { | |
| void init () | |
| { | |
| dict_values_t<OPSTR>::init (); | |
| charStringsOffset = 0; | |
| FDArrayOffset = 0; | |
| } | |
| void fini () { dict_values_t<OPSTR>::fini (); } | |
| int charStringsOffset; | |
| int FDArrayOffset; | |
| }; | |
| struct dict_opset_t : opset_t<number_t> | |
| { | |
| static void process_op (op_code_t op, interp_env_t<number_t>& env) | |
| { | |
| switch (op) { | |
| case OpCode_longintdict: /* 5-byte integer */ | |
| env.argStack.push_longint_from_substr (env.str_ref); | |
| break; | |
| case OpCode_BCD: /* real number */ | |
| env.argStack.push_real (parse_bcd (env.str_ref)); | |
| break; | |
| default: | |
| opset_t<number_t>::process_op (op, env); | |
| break; | |
| } | |
| } | |
| /* Turns CFF's BCD format into strtod understandable string */ | |
| static double parse_bcd (byte_str_ref_t& str_ref) | |
| { | |
| if (unlikely (str_ref.in_error ())) return .0; | |
| enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; | |
| char buf[32] = {0}; | |
| unsigned char byte = 0; | |
| for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count) | |
| { | |
| unsigned nibble; | |
| if (!(i & 1)) | |
| { | |
| if (unlikely (!str_ref.avail ())) break; | |
| byte = str_ref[0]; | |
| str_ref.inc (); | |
| nibble = byte >> 4; | |
| } | |
| else | |
| nibble = byte & 0x0F; | |
| if (unlikely (nibble == RESERVED)) break; | |
| else if (nibble == END) | |
| { | |
| const char *p = buf; | |
| double pv; | |
| if (unlikely (!hb_parse_double (&p, p + count, &pv, true/* whole buffer */))) | |
| break; | |
| return pv; | |
| } | |
| else | |
| { | |
| buf[count] = "0123456789.EE?-?"[nibble]; | |
| if (nibble == EXP_NEG) | |
| { | |
| ++count; | |
| if (unlikely (count == ARRAY_LENGTH (buf))) break; | |
| buf[count] = '-'; | |
| } | |
| } | |
| } | |
| str_ref.set_error (); | |
| return .0; | |
| } | |
| static bool is_hint_op (op_code_t op) | |
| { | |
| switch (op) | |
| { | |
| case OpCode_BlueValues: | |
| case OpCode_OtherBlues: | |
| case OpCode_FamilyBlues: | |
| case OpCode_FamilyOtherBlues: | |
| case OpCode_StemSnapH: | |
| case OpCode_StemSnapV: | |
| case OpCode_StdHW: | |
| case OpCode_StdVW: | |
| case OpCode_BlueScale: | |
| case OpCode_BlueShift: | |
| case OpCode_BlueFuzz: | |
| case OpCode_ForceBold: | |
| case OpCode_LanguageGroup: | |
| case OpCode_ExpansionFactor: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| }; | |
| template <typename VAL=op_str_t> | |
| struct top_dict_opset_t : dict_opset_t | |
| { | |
| static void process_op (op_code_t op, interp_env_t<number_t>& env, top_dict_values_t<VAL> & dictval) | |
| { | |
| switch (op) { | |
| case OpCode_CharStrings: | |
| dictval.charStringsOffset = env.argStack.pop_int (); | |
| env.clear_args (); | |
| break; | |
| case OpCode_FDArray: | |
| dictval.FDArrayOffset = env.argStack.pop_int (); | |
| env.clear_args (); | |
| break; | |
| case OpCode_FontMatrix: | |
| env.clear_args (); | |
| break; | |
| default: | |
| dict_opset_t::process_op (op, env); | |
| break; | |
| } | |
| } | |
| }; | |
| template <typename OPSET, typename PARAM, typename ENV=num_interp_env_t> | |
| struct dict_interpreter_t : interpreter_t<ENV> | |
| { | |
| dict_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {} | |
| bool interpret (PARAM& param) | |
| { | |
| param.init (); | |
| while (SUPER::env.str_ref.avail ()) | |
| { | |
| OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); | |
| if (unlikely (SUPER::env.in_error ())) | |
| return false; | |
| } | |
| return true; | |
| } | |
| private: | |
| typedef interpreter_t<ENV> SUPER; | |
| }; | |
| } /* namespace CFF */ | |
| #endif /* HB_CFF_INTERP_DICT_COMMON_HH */ |