overhauled error handling in CFF interpreter

minimized "if (error) return false" idiom
This commit is contained in:
Michiharu Ariza 2018-10-12 02:16:07 -07:00
parent ca37172ee3
commit 7d99a6cef8
7 changed files with 281 additions and 256 deletions

View File

@ -208,6 +208,8 @@ inline unsigned int OpCode_Size (OpCode op) { return Is_OpCode_ESC (op)? 2: 1; }
#define OpCode_hflex1 Make_OpCode_ESC(36) /* CFF, CFF2 */ #define OpCode_hflex1 Make_OpCode_ESC(36) /* CFF, CFF2 */
#define OpCode_flex1 Make_OpCode_ESC(37) /* CFF, CFF2 */ #define OpCode_flex1 Make_OpCode_ESC(37) /* CFF, CFF2 */
#define OpCode_Invalid 65535
struct Number struct Number
{ {
inline void init (void) inline void init (void)
@ -406,21 +408,29 @@ struct SubByteStr
{ {
str = ByteStr (0); str = ByteStr (0);
offset = 0; offset = 0;
error = false;
} }
inline void fini (void) {} inline void fini (void) {}
inline SubByteStr (const ByteStr &str_, unsigned int offset_ = 0) inline SubByteStr (const ByteStr &str_, unsigned int offset_ = 0)
: str (str_), offset (offset_) {} : str (str_), offset (offset_), error (false) {}
inline void reset (const ByteStr &str_, unsigned int offset_ = 0) inline void reset (const ByteStr &str_, unsigned int offset_ = 0)
{ {
str = str_; str = str_;
offset = offset_; offset = offset_;
error = false;
} }
inline const HBUINT8& operator [] (int i) const { inline const HBUINT8& operator [] (int i) {
return str[offset + i]; if (unlikely ((unsigned int)(offset + i) >= str.len))
{
set_error ();
return Null(HBUINT8);
}
else
return str[offset + i];
} }
inline operator ByteStr (void) const { return ByteStr (str, offset, str.len - offset); } inline operator ByteStr (void) const { return ByteStr (str, offset, str.len - offset); }
@ -428,8 +438,14 @@ struct SubByteStr
inline bool avail (unsigned int count=1) const { return str.check_limit (offset, count); } inline bool avail (unsigned int count=1) const { return str.check_limit (offset, count); }
inline void inc (unsigned int count=1) { offset += count; assert (count <= str.len); } inline void inc (unsigned int count=1) { offset += count; assert (count <= str.len); }
inline void set_error (void) { error = true; }
inline bool in_error (void) const { return error; }
ByteStr str; ByteStr str;
unsigned int offset; /* beginning of the sub-string within str */ unsigned int offset; /* beginning of the sub-string within str */
protected:
bool error;
}; };
/* stack */ /* stack */
@ -438,6 +454,7 @@ struct Stack
{ {
inline void init (void) inline void init (void)
{ {
error = false;
count = 0; count = 0;
elements.init (); elements.init ();
elements.resize (kSizeLimit); elements.resize (kSizeLimit);
@ -450,16 +467,18 @@ struct Stack
elements.fini_deep (); elements.fini_deep ();
} }
inline const ELEM& operator [] (unsigned int i) const
{ return elements[i]; }
inline ELEM& operator [] (unsigned int i) inline ELEM& operator [] (unsigned int i)
{ return elements[i]; } {
if (unlikely (i >= count)) set_error ();
return elements[i];
}
inline void push (const ELEM &v) inline void push (const ELEM &v)
{ {
if (likely (count < elements.len)) if (likely (count < elements.len))
elements[count++] = v; elements[count++] = v;
else
set_error ();
} }
inline ELEM &push (void) inline ELEM &push (void)
@ -467,7 +486,10 @@ struct Stack
if (likely (count < elements.len)) if (likely (count < elements.len))
return elements[count++]; return elements[count++];
else else
{
set_error ();
return Crap(ELEM); return Crap(ELEM);
}
} }
inline ELEM& pop (void) inline ELEM& pop (void)
@ -475,13 +497,18 @@ struct Stack
if (likely (count > 0)) if (likely (count > 0))
return elements[--count]; return elements[--count];
else else
{
set_error ();
return Crap(ELEM); return Crap(ELEM);
}
} }
inline void pop (unsigned int n) inline void pop (unsigned int n)
{ {
if (likely (count >= n)) if (likely (count >= n))
count -= n; count -= n;
else
set_error ();
} }
inline const ELEM& peek (void) inline const ELEM& peek (void)
@ -489,19 +516,24 @@ struct Stack
if (likely (count > 0)) if (likely (count > 0))
return elements[count-1]; return elements[count-1];
else else
{
set_error ();
return Null(ELEM); return Null(ELEM);
}
} }
inline void unpop (void) inline void unpop (void)
{ {
if (likely (count < elements.len)) if (likely (count < elements.len))
count++; count++;
else
set_error ();
} }
inline void clear (void) { count = 0; } inline void clear (void) { count = 0; }
inline bool check_overflow (unsigned int n=1) const { return (n <= kSizeLimit) && (n + count <= kSizeLimit); } inline bool in_error (void) const { return (error || elements.in_error ()); }
inline bool check_underflow (unsigned int n=1) const { return (n <= count); } inline void set_error (void) { error = true; }
inline unsigned int get_count (void) const { return count; } inline unsigned int get_count (void) const { return count; }
inline bool is_empty (void) const { return count == 0; } inline bool is_empty (void) const { return count == 0; }
@ -509,6 +541,7 @@ struct Stack
static const unsigned int kSizeLimit = LIMIT; static const unsigned int kSizeLimit = LIMIT;
protected: protected:
bool error;
unsigned int count; unsigned int count;
hb_vector_t<ELEM, kSizeLimit> elements; hb_vector_t<ELEM, kSizeLimit> elements;
}; };
@ -535,44 +568,41 @@ struct ArgStack : Stack<ARG, 513>
n.set_real (v); n.set_real (v);
} }
inline bool check_pop_num (ARG& n) inline ARG& pop_num (void)
{ {
if (unlikely (!this->check_underflow ())) return this->pop ();
return false;
n = this->pop ();
return true;
} }
inline bool check_pop_num2 (ARG& n1, ARG& n2) inline void pop_num2 (ARG& n1, ARG& n2)
{ {
if (unlikely (!this->check_underflow (2)))
return false;
n2 = this->pop (); n2 = this->pop ();
n1 = this->pop (); n1 = this->pop ();
return true;
} }
inline bool check_pop_int (int& v) inline int pop_int (void)
{ {
if (unlikely (!this->check_underflow ())) return this->pop ().to_int ();
return false;
v = this->pop ().to_int ();
return true;
} }
inline bool check_pop_uint (unsigned int& v) inline unsigned int pop_uint (void)
{ {
int i;
if (unlikely (!check_pop_int (i) || i < 0)) int i = pop_int ();
return false; if (unlikely (i < 0))
v = (unsigned int)i; {
return true; i = 0;
S::set_error ();
}
return (unsigned)i;
} }
inline bool check_pop_delta (hb_vector_t<ARG>& vec, bool even=false) inline void pop_delta (hb_vector_t<ARG>& vec, bool even=false)
{ {
if (even && unlikely ((this->count & 1) != 0)) if (even && unlikely ((this->count & 1) != 0))
return false; {
S::set_error ();
return;
}
float val = 0.0f; float val = 0.0f;
for (unsigned int i = 0; i < S::count; i++) { for (unsigned int i = 0; i < S::count; i++) {
@ -580,21 +610,17 @@ struct ArgStack : Stack<ARG, 513>
ARG *n = vec.push (); ARG *n = vec.push ();
n->set_real (val); n->set_real (val);
} }
return true;
} }
inline bool push_longint_from_substr (SubByteStr& substr) inline void push_longint_from_substr (SubByteStr& substr)
{ {
if (unlikely (!substr.avail (4) || !S::check_overflow (1))) push_int ((substr[0] << 24) | (substr[1] << 16) | (substr[2] << 8) | (substr[3]));
return false;
push_int ((int32_t)*(const HBUINT32*)&substr[0]);
substr.inc (4); substr.inc (4);
return true;
} }
inline bool push_fixed_from_substr (SubByteStr& substr) inline bool push_fixed_from_substr (SubByteStr& substr)
{ {
if (unlikely (!substr.avail (4) || !S::check_overflow (1))) if (unlikely (!substr.avail (4)))
return false; return false;
push_fixed ((int32_t)*(const HBUINT32*)&substr[0]); push_fixed ((int32_t)*(const HBUINT32*)&substr[0]);
substr.inc (4); substr.inc (4);
@ -649,6 +675,7 @@ struct InterpEnv
{ {
substr.reset (str_); substr.reset (str_);
argStack.init (); argStack.init ();
error = false;
} }
inline void fini (void) inline void fini (void)
@ -656,19 +683,27 @@ struct InterpEnv
argStack.fini (); argStack.fini ();
} }
inline bool fetch_op (OpCode &op) inline bool in_error (void) const
{ {
return error || substr.in_error () || argStack.in_error ();
}
inline void set_error (void) { error = true; }
inline OpCode fetch_op (void)
{
OpCode op = OpCode_Reserved2;
if (unlikely (!substr.avail ())) if (unlikely (!substr.avail ()))
return false; return OpCode_Invalid;
op = (OpCode)(unsigned char)substr[0]; op = (OpCode)(unsigned char)substr[0];
if (op == OpCode_escape) { if (op == OpCode_escape) {
if (unlikely (!substr.avail ())) if (unlikely (!substr.avail ()))
return false; return OpCode_Invalid;
op = Make_OpCode_ESC(substr[1]); op = Make_OpCode_ESC(substr[1]);
substr.inc (); substr.inc ();
} }
substr.inc (); substr.inc ();
return true; return op;
} }
inline const ARG& eval_arg (unsigned int i) inline const ARG& eval_arg (unsigned int i)
@ -694,6 +729,8 @@ struct InterpEnv
SubByteStr substr; SubByteStr substr;
ArgStack<ARG> argStack; ArgStack<ARG> argStack;
protected:
bool error;
}; };
typedef InterpEnv<> NumInterpEnv; typedef InterpEnv<> NumInterpEnv;
@ -701,47 +738,38 @@ typedef InterpEnv<> NumInterpEnv;
template <typename ARG=Number> template <typename ARG=Number>
struct OpSet struct OpSet
{ {
static inline bool process_op (OpCode op, InterpEnv<ARG>& env) static inline void process_op (OpCode op, InterpEnv<ARG>& env)
{ {
switch (op) { switch (op) {
case OpCode_shortint: case OpCode_shortint:
if (unlikely (!env.substr.avail (2) || !env.argStack.check_overflow (1))) env.argStack.push_int ((env.substr[0] << 8) | env.substr[1]);
return false;
env.argStack.push_int ((int16_t)*(const HBUINT16*)&env.substr[0]);
env.substr.inc (2); env.substr.inc (2);
break; break;
case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1: case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3: case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
if (unlikely (!env.substr.avail () || !env.argStack.check_overflow (1)))
return false;
env.argStack.push_int ((int16_t)((op - OpCode_TwoBytePosInt0) * 256 + env.substr[0] + 108)); env.argStack.push_int ((int16_t)((op - OpCode_TwoBytePosInt0) * 256 + env.substr[0] + 108));
env.substr.inc (); env.substr.inc ();
break; break;
case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1: case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3: case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
if (unlikely (!env.substr.avail () || !env.argStack.check_overflow (1)))
return false;
env.argStack.push_int ((int16_t)(-(op - OpCode_TwoByteNegInt0) * 256 - env.substr[0] - 108)); env.argStack.push_int ((int16_t)(-(op - OpCode_TwoByteNegInt0) * 256 - env.substr[0] - 108));
env.substr.inc (); env.substr.inc ();
break; break;
default: default:
/* 1-byte integer */ /* 1-byte integer */
if (likely ((OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast)) && if (likely ((OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast)))
likely (env.argStack.check_overflow (1)))
{ {
env.argStack.push_int ((int)op - 139); env.argStack.push_int ((int)op - 139);
} else { } else {
/* invalid unknown operator */ /* invalid unknown operator */
env.clear_args (); env.clear_args ();
return false; env.set_error ();
} }
break; break;
} }
return true;
} }
}; };

View File

@ -98,12 +98,14 @@ struct CSInterpEnv : InterpEnv<ARG>
localSubrs.fini (); localSubrs.fini ();
} }
inline bool in_error (void) const
{
return callStack.in_error () || SUPER::in_error ();
}
inline bool popSubrNum (const BiasedSubrs<SUBRS>& biasedSubrs, unsigned int &subr_num) inline bool popSubrNum (const BiasedSubrs<SUBRS>& biasedSubrs, unsigned int &subr_num)
{ {
int n; int n = SUPER::argStack.pop_int ();
if (unlikely ((!callStack.check_overflow (1) ||
!SUPER::argStack.check_pop_int (n))))
return false;
n += biasedSubrs.bias; n += biasedSubrs.bias;
if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.subrs->count))) if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.subrs->count)))
return false; return false;
@ -124,13 +126,11 @@ struct CSInterpEnv : InterpEnv<ARG>
return true; return true;
} }
inline bool returnFromSubr (void) inline void returnFromSubr (void)
{ {
if (unlikely (!callStack.check_underflow ())) if (unlikely (SUPER::substr.in_error ()))
return false; SUPER::set_error ();
SUPER::substr = callStack.pop (); SUPER::substr = callStack.pop ();
return true;
} }
inline void determine_hintmask_size (void) inline void determine_hintmask_size (void)
@ -212,25 +212,29 @@ struct PathProcsNull
template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=PathProcsNull<ENV, PARAM> > template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=PathProcsNull<ENV, PARAM> >
struct CSOpSet : OpSet<ARG> struct CSOpSet : OpSet<ARG>
{ {
static inline bool process_op (OpCode op, ENV &env, PARAM& param) static inline void process_op (OpCode op, ENV &env, PARAM& param)
{ {
switch (op) { switch (op) {
case OpCode_return: case OpCode_return:
return env.returnFromSubr (); env.returnFromSubr ();
break;
case OpCode_endchar: case OpCode_endchar:
env.set_endchar (true); env.set_endchar (true);
OPSET::flush_args_and_op (op, env, param); OPSET::flush_args_and_op (op, env, param);
break; break;
case OpCode_fixedcs: case OpCode_fixedcs:
return env.argStack.push_fixed_from_substr (env.substr); env.argStack.push_fixed_from_substr (env.substr);
break;
case OpCode_callsubr: case OpCode_callsubr:
return env.callSubr (env.localSubrs); env.callSubr (env.localSubrs);
break;
case OpCode_callgsubr: case OpCode_callgsubr:
return env.callSubr (env.globalSubrs); env.callSubr (env.globalSubrs);
break;
case OpCode_hstem: case OpCode_hstem:
case OpCode_hstemhm: case OpCode_hstemhm:
@ -305,9 +309,9 @@ struct CSOpSet : OpSet<ARG>
break; break;
default: default:
return SUPER::process_op (op, env); SUPER::process_op (op, env);
break;
} }
return true;
} }
static inline void process_hstem (OpCode op, ENV &env, PARAM& param) static inline void process_hstem (OpCode op, ENV &env, PARAM& param)
@ -686,9 +690,8 @@ struct CSInterpreter : Interpreter<ENV>
SUPER::env.set_endchar (false); SUPER::env.set_endchar (false);
for (;;) { for (;;) {
OpCode op; OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
if (unlikely (!SUPER::env.fetch_op (op) || if (unlikely (SUPER::env.in_error ()))
!OPSET::process_op (op, SUPER::env, param)))
return false; return false;
if (SUPER::env.is_endchar ()) if (SUPER::env.is_endchar ())
break; break;

View File

@ -132,28 +132,26 @@ struct TopDictValues : DictValues<OPSTR>
struct DictOpSet : OpSet<Number> struct DictOpSet : OpSet<Number>
{ {
static inline bool process_op (OpCode op, InterpEnv<Number>& env) static inline void process_op (OpCode op, InterpEnv<Number>& env)
{ {
switch (op) { switch (op) {
case OpCode_longintdict: /* 5-byte integer */ case OpCode_longintdict: /* 5-byte integer */
return env.argStack.push_longint_from_substr (env.substr); env.argStack.push_longint_from_substr (env.substr);
break;
case OpCode_BCD: /* real number */ case OpCode_BCD: /* real number */
float v; env.argStack.push_real (parse_bcd (env.substr));
if (unlikely (!env.argStack.check_overflow (1) || !parse_bcd (env.substr, v))) break;
return false;
env.argStack.push_real (v);
return true;
default: default:
return OpSet<Number>::process_op (op, env); OpSet<Number>::process_op (op, env);
break;
} }
return true;
} }
static inline bool parse_bcd (SubByteStr& substr, float& v) static inline float parse_bcd (SubByteStr& substr)
{ {
v = 0.0f; float v = 0.0f;
bool neg = false; bool neg = false;
double int_part = 0; double int_part = 0;
@ -171,7 +169,11 @@ struct DictOpSet : OpSet<Number>
char d; char d;
if ((i & 1) == 0) if ((i & 1) == 0)
{ {
if (!substr.avail ()) return false; if (!substr.avail ())
{
substr.set_error ();
return 0.0f;
}
byte = substr[0]; byte = substr[0];
substr.inc (); substr.inc ();
d = byte >> 4; d = byte >> 4;
@ -182,7 +184,8 @@ struct DictOpSet : OpSet<Number>
switch (d) switch (d)
{ {
case RESERVED: case RESERVED:
return false; substr.set_error ();
return v;
case END: case END:
value = (double)(neg? -int_part: int_part); value = (double)(neg? -int_part: int_part);
@ -195,16 +198,23 @@ struct DictOpSet : OpSet<Number>
else else
value *= pow (10.0, (double)exp_part); value *= pow (10.0, (double)exp_part);
} }
v = (float)value; return (float)value;
return true;
case NEG: case NEG:
if (i != 0) return false; if (i != 0)
{
substr.set_error ();
return 0.0f;
}
neg = true; neg = true;
break; break;
case DECIMAL: case DECIMAL:
if (part != INT_PART) return false; if (part != INT_PART)
{
substr.set_error ();
return v;
}
part = FRAC_PART; part = FRAC_PART;
break; break;
@ -213,7 +223,11 @@ struct DictOpSet : OpSet<Number>
HB_FALLTHROUGH; HB_FALLTHROUGH;
case EXP_POS: case EXP_POS:
if (part == EXP_PART) return false; if (part == EXP_PART)
{
substr.set_error ();
return v;
}
part = EXP_PART; part = EXP_PART;
break; break;
@ -236,7 +250,7 @@ struct DictOpSet : OpSet<Number>
} }
} }
return false; return v;
} }
static inline bool is_hint_op (OpCode op) static inline bool is_hint_op (OpCode op)
@ -267,27 +281,24 @@ struct DictOpSet : OpSet<Number>
template <typename VAL=OpStr> template <typename VAL=OpStr>
struct TopDictOpSet : DictOpSet struct TopDictOpSet : DictOpSet
{ {
static inline bool process_op (OpCode op, InterpEnv<Number>& env, TopDictValues<VAL> & dictval) static inline void process_op (OpCode op, InterpEnv<Number>& env, TopDictValues<VAL> & dictval)
{ {
switch (op) { switch (op) {
case OpCode_CharStrings: case OpCode_CharStrings:
if (unlikely (!env.argStack.check_pop_uint (dictval.charStringsOffset))) dictval.charStringsOffset = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_FDArray: case OpCode_FDArray:
if (unlikely (!env.argStack.check_pop_uint (dictval.FDArrayOffset))) dictval.FDArrayOffset = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_FontMatrix: case OpCode_FontMatrix:
env.clear_args (); env.clear_args ();
break; break;
default: default:
return DictOpSet::process_op (op, env); DictOpSet::process_op (op, env);
break;
} }
return true;
} }
}; };
@ -299,9 +310,8 @@ struct DictInterpreter : Interpreter<ENV>
param.init (); param.init ();
do do
{ {
OpCode op; OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
if (unlikely (!SUPER::env.fetch_op (op) || if (unlikely (SUPER::env.in_error ()))
!OPSET::process_op (op, SUPER::env, param)))
return false; return false;
} while (SUPER::env.substr.avail ()); } while (SUPER::env.substr.avail ());

View File

@ -41,12 +41,17 @@ struct CFF1CSInterpEnv : CSInterpEnv<Number, CFF1Subrs>
SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs); SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
processed_width = false; processed_width = false;
has_width = false; has_width = false;
transient_array.init ();
transient_array.resize (kTransientArraySize);
for (unsigned int i = 0; i < kTransientArraySize; i++) for (unsigned int i = 0; i < kTransientArraySize; i++)
transient_array[i].set_int (0); transient_array[i].set_int (0);
} }
bool check_transient_array_index (unsigned int i) const inline void fini (void)
{ return i < kTransientArraySize; } {
transient_array.fini ();
SUPER::fini ();
}
inline unsigned int check_width (void) inline unsigned int check_width (void)
{ {
@ -69,7 +74,7 @@ struct CFF1CSInterpEnv : CSInterpEnv<Number, CFF1Subrs>
Number width; Number width;
static const unsigned int kTransientArraySize = 32; static const unsigned int kTransientArraySize = 32;
Number transient_array[kTransientArraySize]; hb_vector_t<Number, kTransientArraySize> transient_array;
private: private:
typedef CSInterpEnv<Number, CFF1Subrs> SUPER; typedef CSInterpEnv<Number, CFF1Subrs> SUPER;
@ -78,109 +83,114 @@ struct CFF1CSInterpEnv : CSInterpEnv<Number, CFF1Subrs>
template <typename OPSET, typename PARAM, typename PATH=PathProcsNull<CFF1CSInterpEnv, PARAM> > template <typename OPSET, typename PARAM, typename PATH=PathProcsNull<CFF1CSInterpEnv, PARAM> >
struct CFF1CSOpSet : CSOpSet<Number, OPSET, CFF1CSInterpEnv, PARAM, PATH> struct CFF1CSOpSet : CSOpSet<Number, OPSET, CFF1CSInterpEnv, PARAM, PATH>
{ {
static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, PARAM& param) static inline void process_op (OpCode op, CFF1CSInterpEnv &env, PARAM& param)
{ {
Number n1, n2; Number n1, n2;
switch (op) { switch (op) {
case OpCode_and: case OpCode_and:
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false; env.argStack.pop_num2 (n1, n2);
env.argStack.push_int ((n1.to_real() != 0.0f) && (n2.to_real() != 0.0f)); env.argStack.push_int ((n1.to_real() != 0.0f) && (n2.to_real() != 0.0f));
break; break;
case OpCode_or: case OpCode_or:
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false; env.argStack.pop_num2 (n1, n2);
env.argStack.push_int ((n1.to_real() != 0.0f) || (n2.to_real() != 0.0f)); env.argStack.push_int ((n1.to_real() != 0.0f) || (n2.to_real() != 0.0f));
break; break;
case OpCode_not: case OpCode_not:
if (unlikely (!env.argStack.check_pop_num (n1))) return false; n1 = env.argStack.pop_num ();
env.argStack.push_int (n1.to_real() == 0.0f); env.argStack.push_int (n1.to_real() == 0.0f);
break; break;
case OpCode_abs: case OpCode_abs:
if (unlikely (!env.argStack.check_pop_num (n1))) return false; n1 = env.argStack.pop_num ();
env.argStack.push_real (fabs(n1.to_real ())); env.argStack.push_real (fabs(n1.to_real ()));
break; break;
case OpCode_add: case OpCode_add:
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false; env.argStack.pop_num2 (n1, n2);
env.argStack.push_real (n1.to_real() + n2.to_real()); env.argStack.push_real (n1.to_real() + n2.to_real());
break; break;
case OpCode_sub: case OpCode_sub:
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false; env.argStack.pop_num2 (n1, n2);
env.argStack.push_real (n1.to_real() - n2.to_real()); env.argStack.push_real (n1.to_real() - n2.to_real());
break; break;
case OpCode_div: case OpCode_div:
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false; env.argStack.pop_num2 (n1, n2);
if (unlikely (n2.to_real() == 0.0f)) if (unlikely (n2.to_real() == 0.0f))
env.argStack.push_int (0); env.argStack.push_int (0);
else else
env.argStack.push_real (n1.to_real() / n2.to_real()); env.argStack.push_real (n1.to_real() / n2.to_real());
break; break;
case OpCode_neg: case OpCode_neg:
if (unlikely (!env.argStack.check_pop_num (n1))) return false; n1 = env.argStack.pop_num ();
env.argStack.push_real (-n1.to_real ()); env.argStack.push_real (-n1.to_real ());
break; break;
case OpCode_eq: case OpCode_eq:
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false; env.argStack.pop_num2 (n1, n2);
env.argStack.push_int (n1.to_real() == n2.to_real()); env.argStack.push_int (n1.to_real() == n2.to_real());
break; break;
case OpCode_drop: case OpCode_drop:
if (unlikely (!env.argStack.check_pop_num (n1))) return false; n1 = env.argStack.pop_num ();
break; break;
case OpCode_put: case OpCode_put:
if (unlikely (!env.argStack.check_pop_num2 (n1, n2) || env.argStack.pop_num2 (n1, n2);
!env.check_transient_array_index (n2.to_int ()))) return false;
env.transient_array[n2.to_int ()] = n1; env.transient_array[n2.to_int ()] = n1;
break; break;
case OpCode_get: case OpCode_get:
if (unlikely (!env.argStack.check_pop_num (n1) || n1 = env.argStack.pop_num ();
!env.check_transient_array_index (n1.to_int ()))) return false;
env.argStack.push (env.transient_array[n1.to_int ()]); env.argStack.push (env.transient_array[n1.to_int ()]);
break; break;
case OpCode_ifelse: case OpCode_ifelse:
{ {
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false; env.argStack.pop_num2 (n1, n2);
bool test = n1.to_real () <= n2.to_real (); bool test = n1.to_real () <= n2.to_real ();
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false; env.argStack.pop_num2 (n1, n2);
env.argStack.push (test? n1: n2); env.argStack.push (test? n1: n2);
} }
break; break;
case OpCode_random: case OpCode_random:
if (unlikely (!env.argStack.check_overflow (1))) return false;
env.argStack.push_int (1); /* we can't deal with random behavior; make it constant */ env.argStack.push_int (1); /* we can't deal with random behavior; make it constant */
break; break;
case OpCode_mul: case OpCode_mul:
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false; env.argStack.pop_num2 (n1, n2);
env.argStack.push_real (n1.to_real() * n2.to_real()); env.argStack.push_real (n1.to_real() * n2.to_real());
break; break;
case OpCode_sqrt: case OpCode_sqrt:
if (unlikely (!env.argStack.check_pop_num (n1))) return false; n1 = env.argStack.pop_num ();
env.argStack.push_real ((float)sqrt (n1.to_real ())); env.argStack.push_real ((float)sqrt (n1.to_real ()));
break; break;
case OpCode_dup: case OpCode_dup:
if (unlikely (!env.argStack.check_pop_num (n1))) return false; n1 = env.argStack.pop_num ();
env.argStack.push (n1); env.argStack.push (n1);
env.argStack.push (n1); env.argStack.push (n1);
break; break;
case OpCode_exch: case OpCode_exch:
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false; env.argStack.pop_num2 (n1, n2);
env.argStack.push (n2); env.argStack.push (n2);
env.argStack.push (n1); env.argStack.push (n1);
break; break;
case OpCode_index: case OpCode_index:
{ {
if (unlikely (!env.argStack.check_pop_num (n1))) return false; n1 = env.argStack.pop_num ();
int i = n1.to_int (); int i = n1.to_int ();
if (i < 0) i = 0; if (i < 0) i = 0;
if (unlikely ((unsigned int)i >= env.argStack.get_count () || !env.argStack.check_overflow (1))) return false; if (unlikely ((unsigned int)i >= env.argStack.get_count ()))
{
env.set_error ();
return;
}
env.argStack.push (env.argStack[env.argStack.get_count () - i - 1]); env.argStack.push (env.argStack[env.argStack.get_count () - i - 1]);
} }
break; break;
case OpCode_roll: case OpCode_roll:
{ {
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false; env.argStack.pop_num2 (n1, n2);
int n = n1.to_int (); int n = n1.to_int ();
int j = n2.to_int (); int j = n2.to_int ();
if (unlikely (n < 0 || (unsigned int)n > env.argStack.get_count ())) return false; if (unlikely (n < 0 || (unsigned int)n > env.argStack.get_count ()))
{
env.set_error ();
return;
}
if (likely (n > 0)) if (likely (n > 0))
{ {
if (j < 0) if (j < 0)
@ -195,11 +205,9 @@ struct CFF1CSOpSet : CSOpSet<Number, OPSET, CFF1CSInterpEnv, PARAM, PATH>
} }
break; break;
default: default:
if (unlikely (!SUPER::process_op (op, env, param))) SUPER::process_op (op, env, param);
return false;
break; break;
} }
return true;
} }
static inline void flush_args (CFF1CSInterpEnv &env, PARAM& param, unsigned int start_arg = 0) static inline void flush_args (CFF1CSInterpEnv &env, PARAM& param, unsigned int start_arg = 0)

View File

@ -99,17 +99,16 @@ struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
SUPER::fini (); SUPER::fini ();
} }
inline bool fetch_op (OpCode &op) inline OpCode fetch_op (void)
{ {
if (this->substr.avail ()) if (this->substr.avail ())
return SUPER::fetch_op (op); return SUPER::fetch_op ();
/* make up return or endchar op */ /* make up return or endchar op */
if (this->callStack.check_underflow ()) if (this->callStack.is_empty ())
op = OpCode_return; return OpCode_endchar;
else else
op = OpCode_endchar; return OpCode_return;
return true;
} }
inline const BlendArg& eval_arg (unsigned int i) inline const BlendArg& eval_arg (unsigned int i)
@ -140,14 +139,11 @@ struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
inline void process_vsindex (void) inline void process_vsindex (void)
{ {
unsigned int index; unsigned int index = argStack.pop_uint ();
if (likely (argStack.check_pop_uint (index))) if (do_blend)
{ {
if (do_blend) if (likely (!seen_vsindex && !seen_blend))
{ set_ivs (index);
if (likely (!seen_vsindex && !seen_blend))
set_ivs (index);
}
} }
seen_vsindex = true; seen_vsindex = true;
} }
@ -192,40 +188,45 @@ struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
template <typename OPSET, typename PARAM, typename PATH=PathProcsNull<CFF2CSInterpEnv, PARAM> > template <typename OPSET, typename PARAM, typename PATH=PathProcsNull<CFF2CSInterpEnv, PARAM> >
struct CFF2CSOpSet : CSOpSet<BlendArg, OPSET, CFF2CSInterpEnv, PARAM, PATH> struct CFF2CSOpSet : CSOpSet<BlendArg, OPSET, CFF2CSInterpEnv, PARAM, PATH>
{ {
static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, PARAM& param) static inline void process_op (OpCode op, CFF2CSInterpEnv &env, PARAM& param)
{ {
switch (op) { switch (op) {
case OpCode_callsubr: case OpCode_callsubr:
case OpCode_callgsubr: case OpCode_callgsubr:
/* a subroutine number shoudln't be a blended value */ /* a subroutine number shoudln't be a blended value */
if (unlikely (env.argStack.peek ().blending ())) if (unlikely (env.argStack.peek ().blending ()))
return false; {
return SUPER::process_op (op, env, param); env.set_error ();
break;
}
SUPER::process_op (op, env, param);
break;
case OpCode_blendcs: case OpCode_blendcs:
return OPSET::process_blend (env, param); OPSET::process_blend (env, param);
break;
case OpCode_vsindexcs: case OpCode_vsindexcs:
if (unlikely (env.argStack.peek ().blending ())) if (unlikely (env.argStack.peek ().blending ()))
return false; {
env.set_error ();
break;
}
OPSET::process_vsindex (env, param); OPSET::process_vsindex (env, param);
break; break;
default: default:
return SUPER::process_op (op, env, param); SUPER::process_op (op, env, param);
} }
return true;
} }
static inline bool process_blend (CFF2CSInterpEnv &env, PARAM& param) static inline void process_blend (CFF2CSInterpEnv &env, PARAM& param)
{ {
unsigned int n, k; unsigned int n, k;
env.process_blend (); env.process_blend ();
k = env.get_region_count (); k = env.get_region_count ();
if (unlikely (!env.argStack.check_pop_uint (n) || n = env.argStack.pop_uint ();
(k+1) * n > env.argStack.get_count ()))
return false;
/* copy the blend values into blend array of the default values */ /* copy the blend values into blend array of the default values */
unsigned int start = env.argStack.get_count () - ((k+1) * n); unsigned int start = env.argStack.get_count () - ((k+1) * n);
for (unsigned int i = 0; i < n; i++) for (unsigned int i = 0; i < n; i++)
@ -233,7 +234,6 @@ struct CFF2CSOpSet : CSOpSet<BlendArg, OPSET, CFF2CSInterpEnv, PARAM, PATH>
/* pop off blend values leaving default values now adorned with blend values */ /* pop off blend values leaving default values now adorned with blend values */
env.argStack.pop (k * n); env.argStack.pop (k * n);
return true;
} }
static inline void process_vsindex (CFF2CSInterpEnv &env, PARAM& param) static inline void process_vsindex (CFF2CSInterpEnv &env, PARAM& param)

View File

@ -531,7 +531,7 @@ struct CFF1StringIndex : CFF1Index
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0))) if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0)))
{ {
if (!unlikely (c->extend_min (*this))) if (!unlikely (c->extend_min (this->count)))
return_trace (false); return_trace (false);
count.set (0); count.set (0);
return_trace (true); return_trace (true);
@ -678,7 +678,7 @@ struct CFF1TopDictValues : TopDictValues<CFF1TopDictVal>
struct CFF1TopDictOpSet : TopDictOpSet<CFF1TopDictVal> struct CFF1TopDictOpSet : TopDictOpSet<CFF1TopDictVal>
{ {
static inline bool process_op (OpCode op, CFF1TopDictInterpEnv& env, CFF1TopDictValues& dictval) static inline void process_op (OpCode op, CFF1TopDictInterpEnv& env, CFF1TopDictValues& dictval)
{ {
CFF1TopDictVal val; CFF1TopDictVal val;
val.last_arg_offset = (env.last_offset-1) - dictval.opStart; /* offset to the last argument */ val.last_arg_offset = (env.last_offset-1) - dictval.opStart; /* offset to the last argument */
@ -692,8 +692,7 @@ struct CFF1TopDictOpSet : TopDictOpSet<CFF1TopDictVal>
case OpCode_Weight: case OpCode_Weight:
case OpCode_PostScript: case OpCode_PostScript:
case OpCode_BaseFontName: case OpCode_BaseFontName:
if (unlikely (!env.argStack.check_pop_uint (dictval.nameSIDs[NameDictValues::name_op_to_index (op)]))) dictval.nameSIDs[NameDictValues::name_op_to_index (op)] = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_isFixedPitch: case OpCode_isFixedPitch:
@ -716,56 +715,49 @@ struct CFF1TopDictOpSet : TopDictOpSet<CFF1TopDictVal>
break; break;
case OpCode_CIDCount: case OpCode_CIDCount:
if (unlikely (!env.argStack.check_pop_uint (dictval.cidCount))) dictval.cidCount = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_ROS: case OpCode_ROS:
if (unlikely (!env.argStack.check_pop_uint (dictval.ros_supplement) || dictval.ros_supplement = env.argStack.pop_uint ();
!env.argStack.check_pop_uint (dictval.nameSIDs[NameDictValues::ordering]) || dictval.nameSIDs[NameDictValues::ordering] = env.argStack.pop_uint ();
!env.argStack.check_pop_uint (dictval.nameSIDs[NameDictValues::registry]))) dictval.nameSIDs[NameDictValues::registry] = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_Encoding: case OpCode_Encoding:
if (unlikely (!env.argStack.check_pop_uint (dictval.EncodingOffset))) dictval.EncodingOffset = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_charset: case OpCode_charset:
if (unlikely (!env.argStack.check_pop_uint (dictval.CharsetOffset))) dictval.CharsetOffset = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_FDSelect: case OpCode_FDSelect:
if (unlikely (!env.argStack.check_pop_uint (dictval.FDSelectOffset))) dictval.FDSelectOffset = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_Private: case OpCode_Private:
if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.offset))) dictval.privateDictInfo.offset = env.argStack.pop_uint ();
return false; dictval.privateDictInfo.size = env.argStack.pop_uint ();
if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.size)))
return false;
env.clear_args (); env.clear_args ();
break; break;
default: default:
env.last_offset = env.substr.offset; env.last_offset = env.substr.offset;
if (unlikely (!TopDictOpSet<CFF1TopDictVal>::process_op (op, env, dictval))) TopDictOpSet<CFF1TopDictVal>::process_op (op, env, dictval);
return false;
/* Record this operand below if stack is empty, otherwise done */ /* Record this operand below if stack is empty, otherwise done */
if (!env.argStack.is_empty ()) return true; if (!env.argStack.is_empty ()) return;
break; break;
} }
if (unlikely (env.in_error ())) return;
dictval.addOp (op, env.substr, val); dictval.addOp (op, env.substr, val);
return true;
} }
}; };
@ -789,12 +781,11 @@ struct CFF1FontDictValues : DictValues<OpStr>
struct CFF1FontDictOpSet : DictOpSet struct CFF1FontDictOpSet : DictOpSet
{ {
static inline bool process_op (OpCode op, NumInterpEnv& env, CFF1FontDictValues& dictval) static inline void process_op (OpCode op, NumInterpEnv& env, CFF1FontDictValues& dictval)
{ {
switch (op) { switch (op) {
case OpCode_FontName: case OpCode_FontName:
if (unlikely (!env.argStack.check_pop_uint (dictval.fontName))) dictval.fontName = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_FontMatrix: case OpCode_FontMatrix:
@ -802,22 +793,20 @@ struct CFF1FontDictOpSet : DictOpSet
env.clear_args (); env.clear_args ();
break; break;
case OpCode_Private: case OpCode_Private:
if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.offset))) dictval.privateDictInfo.offset = env.argStack.pop_uint ();
return false; dictval.privateDictInfo.size = env.argStack.pop_uint ();
if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.size)))
return false;
env.clear_args (); env.clear_args ();
break; break;
default: default:
if (unlikely (!DictOpSet::process_op (op, env))) DictOpSet::process_op (op, env);
return false; if (!env.argStack.is_empty ()) return;
if (!env.argStack.is_empty ()) return true;
break; break;
} }
if (unlikely (env.in_error ())) return;
dictval.addOp (op, env.substr); dictval.addOp (op, env.substr);
return true;
} }
}; };
@ -856,7 +845,7 @@ typedef CFF1PrivateDictValues_Base<NumDictVal> CFF1PrivateDictValues;
struct CFF1PrivateDictOpSet : DictOpSet struct CFF1PrivateDictOpSet : DictOpSet
{ {
static inline bool process_op (OpCode op, NumInterpEnv& env, CFF1PrivateDictValues& dictval) static inline void process_op (OpCode op, NumInterpEnv& env, CFF1PrivateDictValues& dictval)
{ {
NumDictVal val; NumDictVal val;
val.init (); val.init ();
@ -868,8 +857,7 @@ struct CFF1PrivateDictOpSet : DictOpSet
case OpCode_FamilyOtherBlues: case OpCode_FamilyOtherBlues:
case OpCode_StemSnapH: case OpCode_StemSnapH:
case OpCode_StemSnapV: case OpCode_StemSnapV:
if (unlikely (!env.argStack.check_pop_delta (val.multi_val))) env.argStack.pop_delta (val.multi_val);
return false;
break; break;
case OpCode_StdHW: case OpCode_StdHW:
case OpCode_StdVW: case OpCode_StdVW:
@ -882,31 +870,29 @@ struct CFF1PrivateDictOpSet : DictOpSet
case OpCode_initialRandomSeed: case OpCode_initialRandomSeed:
case OpCode_defaultWidthX: case OpCode_defaultWidthX:
case OpCode_nominalWidthX: case OpCode_nominalWidthX:
if (unlikely (!env.argStack.check_pop_num (val.single_val))) val.single_val = env.argStack.pop_num ();
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_Subrs: case OpCode_Subrs:
if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset))) dictval.subrsOffset = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
default: default:
if (unlikely (!DictOpSet::process_op (op, env))) DictOpSet::process_op (op, env);
return false; if (!env.argStack.is_empty ()) return;
if (!env.argStack.is_empty ()) return true;
break; break;
} }
if (unlikely (env.in_error ())) return;
dictval.addOp (op, env.substr, val); dictval.addOp (op, env.substr, val);
return true;
} }
}; };
struct CFF1PrivateDictOpSet_Subset : DictOpSet struct CFF1PrivateDictOpSet_Subset : DictOpSet
{ {
static inline bool process_op (OpCode op, NumInterpEnv& env, CFF1PrivateDictValues_Subset& dictval) static inline void process_op (OpCode op, NumInterpEnv& env, CFF1PrivateDictValues_Subset& dictval)
{ {
switch (op) { switch (op) {
case OpCode_BlueValues: case OpCode_BlueValues:
@ -930,20 +916,19 @@ struct CFF1PrivateDictOpSet_Subset : DictOpSet
break; break;
case OpCode_Subrs: case OpCode_Subrs:
if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset))) dictval.subrsOffset = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
default: default:
if (unlikely (!DictOpSet::process_op (op, env))) DictOpSet::process_op (op, env);
return false; if (!env.argStack.is_empty ()) return;
if (!env.argStack.is_empty ()) return true;
break; break;
} }
if (unlikely (env.in_error ())) return;
dictval.addOp (op, env.substr); dictval.addOp (op, env.substr);
return true;
} }
}; };

View File

@ -176,7 +176,7 @@ struct CFF2TopDictValues : TopDictValues<>
struct CFF2TopDictOpSet : TopDictOpSet<> struct CFF2TopDictOpSet : TopDictOpSet<>
{ {
static inline bool process_op (OpCode op, NumInterpEnv& env, CFF2TopDictValues& dictval) static inline void process_op (OpCode op, NumInterpEnv& env, CFF2TopDictValues& dictval)
{ {
switch (op) { switch (op) {
case OpCode_FontMatrix: case OpCode_FontMatrix:
@ -189,25 +189,23 @@ struct CFF2TopDictOpSet : TopDictOpSet<>
break; break;
case OpCode_vstore: case OpCode_vstore:
if (unlikely (!env.argStack.check_pop_uint (dictval.vstoreOffset))) dictval.vstoreOffset = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_FDSelect: case OpCode_FDSelect:
if (unlikely (!env.argStack.check_pop_uint (dictval.FDSelectOffset))) dictval.FDSelectOffset = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
default: default:
if (unlikely (!SUPER::process_op (op, env, dictval))) SUPER::process_op (op, env, dictval);
return false;
/* Record this operand below if stack is empty, otherwise done */ /* Record this operand below if stack is empty, otherwise done */
if (!env.argStack.is_empty ()) return true; if (!env.argStack.is_empty ()) return;
} }
if (unlikely (env.in_error ())) return;
dictval.addOp (op, env.substr); dictval.addOp (op, env.substr);
return true;
} }
typedef TopDictOpSet<> SUPER; typedef TopDictOpSet<> SUPER;
@ -231,26 +229,24 @@ struct CFF2FontDictValues : DictValues<OpStr>
struct CFF2FontDictOpSet : DictOpSet struct CFF2FontDictOpSet : DictOpSet
{ {
static inline bool process_op (OpCode op, NumInterpEnv& env, CFF2FontDictValues& dictval) static inline void process_op (OpCode op, NumInterpEnv& env, CFF2FontDictValues& dictval)
{ {
switch (op) { switch (op) {
case OpCode_Private: case OpCode_Private:
if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.offset))) dictval.privateDictInfo.offset = env.argStack.pop_uint ();
return false; dictval.privateDictInfo.size = env.argStack.pop_uint ();
if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.size)))
return false;
env.clear_args (); env.clear_args ();
break; break;
default: default:
if (unlikely (!SUPER::process_op (op, env))) SUPER::process_op (op, env);
return false;
if (!env.argStack.is_empty ()) if (!env.argStack.is_empty ())
return true; return;
} }
if (unlikely (env.in_error ())) return;
dictval.addOp (op, env.substr); dictval.addOp (op, env.substr);
return true;
} }
private: private:
@ -303,10 +299,9 @@ struct CFF2PrivDictInterpEnv : NumInterpEnv
inline void process_vsindex (void) inline void process_vsindex (void)
{ {
unsigned int index; if (likely (!seen_vsindex))
if (likely (!seen_vsindex && argStack.check_pop_uint (index)))
{ {
set_ivs (argStack.check_pop_uint (index)); set_ivs (argStack.pop_uint ());
} }
seen_vsindex = true; seen_vsindex = true;
} }
@ -321,7 +316,7 @@ struct CFF2PrivDictInterpEnv : NumInterpEnv
struct CFF2PrivateDictOpSet : DictOpSet struct CFF2PrivateDictOpSet : DictOpSet
{ {
static inline bool process_op (OpCode op, CFF2PrivDictInterpEnv& env, CFF2PrivateDictValues& dictval) static inline void process_op (OpCode op, CFF2PrivDictInterpEnv& env, CFF2PrivateDictValues& dictval)
{ {
NumDictVal val; NumDictVal val;
val.init (); val.init ();
@ -334,8 +329,7 @@ struct CFF2PrivateDictOpSet : DictOpSet
case OpCode_BlueFuzz: case OpCode_BlueFuzz:
case OpCode_ExpansionFactor: case OpCode_ExpansionFactor:
case OpCode_LanguageGroup: case OpCode_LanguageGroup:
if (unlikely (!env.argStack.check_pop_num (val.single_val))) val.single_val = env.argStack.pop_num ();
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_BlueValues: case OpCode_BlueValues:
@ -344,13 +338,11 @@ struct CFF2PrivateDictOpSet : DictOpSet
case OpCode_FamilyOtherBlues: case OpCode_FamilyOtherBlues:
case OpCode_StemSnapH: case OpCode_StemSnapH:
case OpCode_StemSnapV: case OpCode_StemSnapV:
if (unlikely (!env.argStack.check_pop_delta (val.multi_val))) env.argStack.pop_delta (val.multi_val);
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_Subrs: case OpCode_Subrs:
if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset))) dictval.subrsOffset = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
case OpCode_vsindexdict: case OpCode_vsindexdict:
@ -361,20 +353,20 @@ struct CFF2PrivateDictOpSet : DictOpSet
break; break;
default: default:
if (unlikely (!DictOpSet::process_op (op, env))) DictOpSet::process_op (op, env);
return false; if (!env.argStack.is_empty ()) return;
if (!env.argStack.is_empty ()) return true;
break; break;
} }
if (unlikely (env.in_error ())) return;
dictval.addOp (op, env.substr, val); dictval.addOp (op, env.substr, val);
return true;
} }
}; };
struct CFF2PrivateDictOpSet_Subset : DictOpSet struct CFF2PrivateDictOpSet_Subset : DictOpSet
{ {
static inline bool process_op (OpCode op, CFF2PrivDictInterpEnv& env, CFF2PrivateDictValues_Subset& dictval) static inline void process_op (OpCode op, CFF2PrivDictInterpEnv& env, CFF2PrivateDictValues_Subset& dictval)
{ {
switch (op) { switch (op) {
case OpCode_BlueValues: case OpCode_BlueValues:
@ -395,23 +387,22 @@ struct CFF2PrivateDictOpSet_Subset : DictOpSet
case OpCode_blenddict: case OpCode_blenddict:
env.clear_args (); env.clear_args ();
return true; return;
case OpCode_Subrs: case OpCode_Subrs:
if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset))) dictval.subrsOffset = env.argStack.pop_uint ();
return false;
env.clear_args (); env.clear_args ();
break; break;
default: default:
if (unlikely (!SUPER::process_op (op, env))) SUPER::process_op (op, env);
return false; if (!env.argStack.is_empty ()) return;
if (!env.argStack.is_empty ()) return true;
break; break;
} }
if (unlikely (env.in_error ())) return;
dictval.addOp (op, env.substr); dictval.addOp (op, env.substr);
return true;
} }
private: private: