1 /* 2 * Copyright © 2018 Adobe Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Adobe Author(s): Michiharu Ariza 25 */ 26 #ifndef HB_CFF_INTERP_DICT_COMMON_HH 27 #define HB_CFF_INTERP_DICT_COMMON_HH 28 29 #include "hb-cff-interp-common.hh" 30 #include <math.h> 31 #include <float.h> 32 33 namespace CFF { 34 35 using namespace OT; 36 37 /* an opstr and the parsed out dict value(s) */ 38 struct DictVal : OpStr 39 { initCFF::DictVal40 void init () { single_val.set_int (0); } finiCFF::DictVal41 void fini () {} 42 43 Number single_val; 44 }; 45 46 typedef DictVal NumDictVal; 47 48 template <typename VAL> struct DictValues : ParsedValues<VAL> {}; 49 50 template <typename OPSTR=OpStr> 51 struct TopDictValues : DictValues<OPSTR> 52 { initCFF::TopDictValues53 void init () 54 { 55 DictValues<OPSTR>::init (); 56 charStringsOffset = 0; 57 FDArrayOffset = 0; 58 } finiCFF::TopDictValues59 void fini () { DictValues<OPSTR>::fini (); } 60 calculate_serialized_op_sizeCFF::TopDictValues61 unsigned int calculate_serialized_op_size (const OPSTR& opstr) const 62 { 63 switch (opstr.op) 64 { 65 case OpCode_CharStrings: 66 case OpCode_FDArray: 67 return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); 68 69 default: 70 return opstr.str.len; 71 } 72 } 73 74 unsigned int charStringsOffset; 75 unsigned int FDArrayOffset; 76 }; 77 78 struct DictOpSet : OpSet<Number> 79 { process_opCFF::DictOpSet80 static void process_op (OpCode op, InterpEnv<Number>& env) 81 { 82 switch (op) { 83 case OpCode_longintdict: /* 5-byte integer */ 84 env.argStack.push_longint_from_substr (env.substr); 85 break; 86 87 case OpCode_BCD: /* real number */ 88 env.argStack.push_real (parse_bcd (env.substr)); 89 break; 90 91 default: 92 OpSet<Number>::process_op (op, env); 93 break; 94 } 95 } 96 parse_bcdCFF::DictOpSet97 static double parse_bcd (SubByteStr& substr) 98 { 99 bool neg = false; 100 double int_part = 0; 101 uint64_t frac_part = 0; 102 uint32_t frac_count = 0; 103 bool exp_neg = false; 104 uint32_t exp_part = 0; 105 bool exp_overflow = false; 106 enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART; 107 enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; 108 const uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */ 109 const uint32_t MAX_EXP = 0x7FFu; /* 1^11-1 */ 110 111 double value = 0.0; 112 unsigned char byte = 0; 113 for (uint32_t i = 0;; i++) 114 { 115 char d; 116 if ((i & 1) == 0) 117 { 118 if (!substr.avail ()) 119 { 120 substr.set_error (); 121 return 0.0; 122 } 123 byte = substr[0]; 124 substr.inc (); 125 d = byte >> 4; 126 } 127 else 128 d = byte & 0x0F; 129 130 switch (d) 131 { 132 case RESERVED: 133 substr.set_error (); 134 return value; 135 136 case END: 137 value = (double)(neg? -int_part: int_part); 138 if (frac_count > 0) 139 { 140 double frac = (frac_part / pow (10.0, (double)frac_count)); 141 if (neg) frac = -frac; 142 value += frac; 143 } 144 if (unlikely (exp_overflow)) 145 { 146 if (value == 0.0) 147 return value; 148 if (exp_neg) 149 return neg? -DBL_MIN: DBL_MIN; 150 else 151 return neg? -DBL_MAX: DBL_MAX; 152 } 153 if (exp_part != 0) 154 { 155 if (exp_neg) 156 value /= pow (10.0, (double)exp_part); 157 else 158 value *= pow (10.0, (double)exp_part); 159 } 160 return value; 161 162 case NEG: 163 if (i != 0) 164 { 165 substr.set_error (); 166 return 0.0; 167 } 168 neg = true; 169 break; 170 171 case DECIMAL: 172 if (part != INT_PART) 173 { 174 substr.set_error (); 175 return value; 176 } 177 part = FRAC_PART; 178 break; 179 180 case EXP_NEG: 181 exp_neg = true; 182 HB_FALLTHROUGH; 183 184 case EXP_POS: 185 if (part == EXP_PART) 186 { 187 substr.set_error (); 188 return value; 189 } 190 part = EXP_PART; 191 break; 192 193 default: 194 switch (part) { 195 default: 196 case INT_PART: 197 int_part = (int_part * 10) + d; 198 break; 199 200 case FRAC_PART: 201 if (likely (frac_part <= MAX_FRACT / 10)) 202 { 203 frac_part = (frac_part * 10) + (unsigned)d; 204 frac_count++; 205 } 206 break; 207 208 case EXP_PART: 209 if (likely (exp_part * 10 + d <= MAX_EXP)) 210 { 211 exp_part = (exp_part * 10) + d; 212 } 213 else 214 exp_overflow = true; 215 break; 216 } 217 } 218 } 219 220 return value; 221 } 222 is_hint_opCFF::DictOpSet223 static bool is_hint_op (OpCode op) 224 { 225 switch (op) 226 { 227 case OpCode_BlueValues: 228 case OpCode_OtherBlues: 229 case OpCode_FamilyBlues: 230 case OpCode_FamilyOtherBlues: 231 case OpCode_StemSnapH: 232 case OpCode_StemSnapV: 233 case OpCode_StdHW: 234 case OpCode_StdVW: 235 case OpCode_BlueScale: 236 case OpCode_BlueShift: 237 case OpCode_BlueFuzz: 238 case OpCode_ForceBold: 239 case OpCode_LanguageGroup: 240 case OpCode_ExpansionFactor: 241 return true; 242 default: 243 return false; 244 } 245 } 246 }; 247 248 template <typename VAL=OpStr> 249 struct TopDictOpSet : DictOpSet 250 { process_opCFF::TopDictOpSet251 static void process_op (OpCode op, InterpEnv<Number>& env, TopDictValues<VAL> & dictval) 252 { 253 switch (op) { 254 case OpCode_CharStrings: 255 dictval.charStringsOffset = env.argStack.pop_uint (); 256 env.clear_args (); 257 break; 258 case OpCode_FDArray: 259 dictval.FDArrayOffset = env.argStack.pop_uint (); 260 env.clear_args (); 261 break; 262 case OpCode_FontMatrix: 263 env.clear_args (); 264 break; 265 default: 266 DictOpSet::process_op (op, env); 267 break; 268 } 269 } 270 }; 271 272 template <typename OPSET, typename PARAM, typename ENV=NumInterpEnv> 273 struct DictInterpreter : Interpreter<ENV> 274 { interpretCFF::DictInterpreter275 bool interpret (PARAM& param) 276 { 277 param.init (); 278 while (SUPER::env.substr.avail ()) 279 { 280 OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); 281 if (unlikely (SUPER::env.in_error ())) 282 return false; 283 } 284 285 return true; 286 } 287 288 private: 289 typedef Interpreter<ENV> SUPER; 290 }; 291 292 } /* namespace CFF */ 293 294 #endif /* HB_CFF_INTERP_DICT_COMMON_HH */ 295