summaryrefslogtreecommitdiff
path: root/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/t1lint/cscheck.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/t1lint/cscheck.cc')
-rw-r--r--Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/t1lint/cscheck.cc528
1 files changed, 528 insertions, 0 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/t1lint/cscheck.cc b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/t1lint/cscheck.cc
new file mode 100644
index 00000000000..f39a040a014
--- /dev/null
+++ b/Build/source/texk/lcdf-typetools/lcdf-typetools-2.99/t1lint/cscheck.cc
@@ -0,0 +1,528 @@
+/* cscheck.{cc,hh} -- checking Type 1 charstrings for validity
+ *
+ * Copyright (c) 1999-2012 Eddie Kohler
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version. This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "cscheck.hh"
+#include <efont/t1item.hh>
+#include <lcdf/error.hh>
+#include <efont/t1unparser.hh>
+
+using namespace Efont;
+
+#define CHECK_STACK_GE(numargs) do { if (size() < numargs) return error(errUnderflow, cmd); } while (0)
+#define CHECK_STACK_EQ(numargs) do { CHECK_STACK_GE(numargs); if (size() > numargs) _errh->warning("too many arguments to %<%s%> (have %d, expected %d)", Charstring::command_name(cmd).c_str(), size(), numargs); } while (0)
+#define CHECK_STACK_CPEQ(numargs) do { CHECK_STACK_EQ(numargs); if (!_cp_exists) return error(errCurrentPoint, cmd); } while (0)
+
+
+CharstringChecker::CharstringChecker()
+ : CharstringInterp(), _errh(0)
+{
+ set_careful(true);
+}
+
+CharstringChecker::CharstringChecker(const Vector<double> &weight)
+ : CharstringInterp(weight), _errh(0)
+{
+ set_careful(true);
+}
+
+
+void
+CharstringChecker::stem(double y, double dy, const char *cmd_name)
+{
+ bool is_v = (cmd_name[0] == 'v');
+ Vector<double> &hints = (is_v ? _h_vstem : _h_hstem);
+ const char *dimen_name = (is_v ? "x" : "y");
+ if (dy < 0) {
+ y += dy;
+ dy = -dy;
+ }
+ if (dy < 0.5)
+ _errh->warning("small delta-%s in %<%s%> (%g)", dimen_name, cmd_name, dy);
+ for (int i = 0; i < hints.size(); i += 2)
+ if ((hints[i] >= y && hints[i+1] <= y)
+ || (hints[i] >= y+dy && hints[i+1] <= y+dy))
+ _errh->warning("overlapping %<%s%> hints", cmd_name);
+ hints.push_back(y);
+ hints.push_back(y+dy);
+}
+
+void
+CharstringChecker::check_stem3(const char *cmd_name)
+{
+ bool is_v = (cmd_name[0] == 'v');
+ Vector<double> &hints = (is_v ? _h_vstem : _h_hstem);
+ Vector<double> &old_hints = (is_v ? _h_vstem3 : _h_hstem3);
+ assert(hints.size() == 6);
+
+ // sort hints
+ int i0, i1, i2;
+ if (hints[0] > hints[2])
+ i0 = 2, i1 = 0;
+ else
+ i0 = 0, i1 = 2;
+ if (hints[4] < hints[i0])
+ i2 = i1, i1 = i0, i0 = 4;
+ else if (hints[4] < hints[i1])
+ i2 = i1, i1 = 4;
+ else
+ i2 = 4;
+
+ // check constraints. count "almost equal" as equal
+ double stemw0 = hints[i0+1] - hints[i0];
+ double stemw2 = hints[i2+1] - hints[i2];
+ if ((int)(1024*(stemw0 - stemw2) + .5) != 0)
+ _errh->error("bad %<%s%>: extreme stem widths unequal (%g, %g)", cmd_name, stemw0, stemw2);
+
+ double c0 = (hints[i0] + hints[i0+1])/2;
+ double c1 = (hints[i1] + hints[i1+1])/2;
+ double c2 = (hints[i2] + hints[i2+1])/2;
+ if ((int)(1024*((c1 - c0) - (c2 - c1)) + .5) != 0)
+ _errh->error("bad %<%s%>: stem gaps unequal (%g, %g)", cmd_name, c1-c0, c2-c1);
+
+ // compare to old hints
+ if (old_hints.size()) {
+ for (int i = 0; i < old_hints.size(); i++)
+ if (hints[i] != old_hints[i]) {
+ _errh->warning("%<%s%> conflicts with old %<%s%>", cmd_name, cmd_name);
+ break;
+ }
+ }
+ old_hints = hints;
+}
+
+void
+CharstringChecker::moveto(double, double, bool cp_exists)
+{
+ _cp_exists = cp_exists;
+}
+
+void
+CharstringChecker::rmoveto(double, double)
+{
+ _cp_exists = true;
+ _just_flexed = false;
+}
+
+void
+CharstringChecker::rlineto(double, double)
+{
+}
+
+void
+CharstringChecker::rrcurveto(double, double, double, double, double, double)
+{
+}
+
+
+bool
+CharstringChecker::error(int which, int data)
+{
+ CharstringInterp::error(which, data);
+ _errh->error("%s", error_string().c_str());
+ return false;
+}
+
+bool
+CharstringChecker::callothersubr()
+{
+ int othersubrnum = (int)top(0);
+ int n = (int)top(1);
+ int i;
+
+ pop(2);
+ if (othersubrnum < 0 || size() < n) return false;
+
+ if (!_started && (othersubrnum < 14 || othersubrnum > 18))
+ _errh->warning("first command not %<hsbw%> or %<sbw%>");
+
+ switch (othersubrnum) {
+
+ case 0: // Flex
+ if (n != 3) {
+ _errh->error("wrong number of arguments to Flex");
+ goto unknown;
+ }
+ if (!_flex) {
+ _errh->error("no Flex in progress");
+ pop(3);
+ return false;
+ } else if (ps_size() != 16) {
+ _errh->error("Flex needs 16 arguments, have %d", ps_size());
+ pop(3);
+ return false;
+ }
+ //_connect = _flex_connect;
+#if 0
+ addbezier(Point(ps_at(0), ps_at(1)),
+ Point(ps_at(4), ps_at(5)),
+ Point(ps_at(6), ps_at(7)),
+ Point(ps_at(8), ps_at(9)));
+ addbezier(Point(ps_at(8), ps_at(9)),
+ Point(ps_at(10), ps_at(11)),
+ Point(ps_at(12), ps_at(13)),
+ Point(ps_at(14), ps_at(15)));
+#endif
+ ps_clear();
+ ps_push(top(0));
+ ps_push(top(1));
+ _flex = false;
+ break;
+
+ case 1: // Flex
+ if (n != 0) {
+ _errh->error("wrong number of arguments to Flex");
+ goto unknown;
+ }
+ ps_clear();
+ ps_push(_cp.x);
+ ps_push(_cp.y);
+ _flex = true;
+ _just_flexed = true;
+ //_flex_connect = _connect;
+ break;
+
+ case 2: // Flex
+ if (n != 0) {
+ _errh->error("wrong number of arguments to Flex");
+ goto unknown;
+ }
+ if (!_flex)
+ return error(errFlex, 0);
+ if (_just_flexed)
+ _errh->error("Flex control points must be separated by a moveto");
+ ps_push(_cp.x);
+ ps_push(_cp.y);
+ _just_flexed = true;
+ break;
+
+ case 3: // hint replacement
+ if (n != 1) {
+ _errh->error("wrong number of arguments to hint replacement");
+ goto unknown;
+ }
+ ps_clear();
+ ps_push(top());
+ _h_hstem.clear();
+ _h_vstem.clear();
+ break;
+
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ return mm_command(othersubrnum, n);
+
+ default: // unknown
+ unknown:
+ _errh->warning("unknown callothersubr %<%d%>", othersubrnum);
+ ps_clear();
+ for (i = 0; i < n; i++)
+ ps_push(top(i));
+ break;
+
+ }
+
+ pop(n);
+ return true;
+}
+
+//#define DEBUG(s) printf s
+#define DEBUG(s)
+
+bool
+CharstringChecker::type1_command(int cmd)
+{
+ if (_subrno < 0)
+ ++_ncommand;
+ if (cmd == Cs::cCallsubr) {
+ int old_subrno = _subrno;
+ _subrno = (size() > 1 ? (int) top(0) : -300);
+ bool result = callsubr_command();
+ _subrno = old_subrno;
+ return result;
+ } else if (cmd == Cs::cCallothersubr) {
+ CHECK_STACK_GE(2);
+ return callothersubr();
+ } else if (cmd == Cs::cReturn) {
+ return false;
+ } else if (cmd == Cs::cPop || cmd == Cs::cDiv) {
+ return arith_command(cmd);
+ }
+
+ if (cmd != Cs::cHsbw && cmd != Cs::cSbw) {
+ if (!_started)
+ _errh->warning("first command not %<hsbw%> or %<sbw%>");
+ } else {
+ if (_started)
+ _errh->error("duplicate %<hsbw%> or %<sbw%>");
+ }
+ _started = true;
+
+ switch (cmd) {
+
+ case Cs::cHsbw:
+ CHECK_STACK_EQ(2);
+ moveto(at(0), 0, false);
+ clear();
+ break;
+
+ case Cs::cSbw:
+ CHECK_STACK_EQ(4);
+ moveto(at(0), at(1), false);
+ clear();
+ break;
+
+ case Cs::cClosepath:
+ _cp_exists = false;
+ clear();
+ break;
+
+ case Cs::cHlineto:
+ CHECK_STACK_CPEQ(1);
+ rlineto(at(0), 0);
+ clear();
+ break;
+
+ case Cs::cHmoveto:
+ CHECK_STACK_EQ(1);
+ rmoveto(at(0), 0);
+ clear();
+ break;
+
+ case Cs::cHvcurveto:
+ CHECK_STACK_CPEQ(4);
+ rrcurveto(at(0), 0, at(1), at(2), 0, at(3));
+ clear();
+ break;
+
+ case Cs::cRlineto:
+ CHECK_STACK_CPEQ(2);
+ rlineto(at(0), at(1));
+ clear();
+ break;
+
+ case Cs::cRmoveto:
+ CHECK_STACK_EQ(2);
+ rmoveto(at(0), at(1));
+ clear();
+ break;
+
+ case Cs::cRrcurveto:
+ CHECK_STACK_CPEQ(6);
+ rrcurveto(at(0), at(1), at(2), at(3), at(4), at(5));
+ clear();
+ break;
+
+ case Cs::cVhcurveto:
+ CHECK_STACK_CPEQ(4);
+ rrcurveto(0, at(0), at(1), at(2), at(3), 0);
+ clear();
+ break;
+
+ case Cs::cVlineto:
+ CHECK_STACK_CPEQ(1);
+ rlineto(0, at(0));
+ clear();
+ break;
+
+ case Cs::cVmoveto:
+ CHECK_STACK_EQ(1);
+ rmoveto(0, at(0));
+ clear();
+ break;
+
+ case Cs::cHstem:
+ CHECK_STACK_EQ(2);
+ if (_hstem3 && !_hstem)
+ _errh->error("charstring has both %<hstem%> and %<hstem3%>");
+ _hstem = true;
+ stem(at(0), at(1), "hstem");
+ clear();
+ break;
+
+ case Cs::cVstem:
+ CHECK_STACK_EQ(2);
+ if (_vstem3 && !_vstem)
+ _errh->error("charstring has both %<vstem%> and %<vstem3%>");
+ _vstem = true;
+ stem(at(0), at(1), "vstem");
+ clear();
+ break;
+
+ case Cs::cEndchar:
+ set_done();
+ return false;
+
+ case Cs::cDotsection:
+ break;
+
+ case Cs::cVstem3:
+ CHECK_STACK_EQ(6);
+ if (_vstem && !_vstem3)
+ _errh->error("charstring has both %<vstem%> and %<vstem3%>");
+ _vstem3 = true;
+ _h_vstem.clear();
+ stem(at(0), at(1), "vstem3");
+ stem(at(2), at(3), "vstem3");
+ stem(at(4), at(5), "vstem3");
+ check_stem3("vstem3");
+ clear();
+ break;
+
+ case Cs::cHstem3:
+ CHECK_STACK_EQ(6);
+ if (_hstem && !_hstem3)
+ _errh->error("charstring has both %<hstem%> and %<hstem3%>");
+ _hstem3 = true;
+ _h_hstem.clear();
+ stem(at(0), at(1), "hstem3");
+ stem(at(2), at(3), "hstem3");
+ stem(at(4), at(5), "hstem3");
+ check_stem3("hstem3");
+ clear();
+ break;
+
+ case Cs::cSeac: {
+ CHECK_STACK_EQ(5);
+#if 0
+ double asb = at(0);
+ double adx = at(1);
+ double ady = at(2);
+ int bchar = (int)at(3);
+ int achar = (int)at(4);
+
+ double ax = adx - asb + _sidebearing.x;
+ double ay = ady + _sidebearing.y;
+
+ Point real_sidebearing = _sidebearing;
+ Point real_char_width = _char_width;
+ Point original_origin = _origin;
+
+ Type1Encoding *adobe = Type1Encoding::standard_encoding();
+ if (!adobe)
+ return error(errInternal, cmd);
+ Type1Charstring *t1cs = get_glyph((*adobe)[achar]);
+ if (!t1cs) ERROR(errGlyph);
+ _origin = Point(ax, ay);
+ init();
+ t1cs->run(*this);
+ _origin = original_origin;
+ if (error()) return false;
+
+ t1cs = get_glyph((*adobe)[bchar]);
+ if (!t1cs) ERROR(errGlyph);
+ init();
+ t1cs->run(*this);
+ _sidebearing = real_sidebearing;
+ _char_width = real_char_width;
+#endif
+ return false;
+ }
+
+ case Cs::cSetcurrentpoint:
+ CHECK_STACK_EQ(2);
+ _cp = Point(at(0), at(1));
+ _cp_exists = true;
+ clear();
+ break;
+
+ case Cs::cPut:
+ case Cs::cGet:
+ case Cs::cStore:
+ case Cs::cLoad:
+ return vector_command(cmd);
+
+ default:
+ return arith_command(cmd);
+
+ }
+
+ return true;
+}
+
+bool
+CharstringChecker::check(const CharstringContext &g, ErrorHandler *errh)
+{
+ CharstringCheckerErrorHandler<CharstringChecker> merrh(errh, this);
+ _errh = &merrh;
+ int old_errors = errh->nerrors();
+
+ _started = false;
+ _flex = false;
+ _hstem = _hstem3 = _vstem = _vstem3 = _just_flexed = false;
+ _h_hstem.clear();
+ _h_vstem.clear();
+ _h_hstem3.clear();
+ _h_vstem3.clear();
+ _ncommand = 0;
+ _subrno = -1;
+
+ CharstringInterp::interpret(g);
+
+ return errh->nerrors() == old_errors;
+}
+
+
+
+CharstringSubrChecker::CharstringSubrChecker()
+ : CharstringInterp(), _errh(0)
+{
+ set_careful(true);
+}
+
+CharstringSubrChecker::CharstringSubrChecker(const Vector<double> &weight)
+ : CharstringInterp(weight), _errh(0)
+{
+ set_careful(true);
+}
+
+bool
+CharstringSubrChecker::error(int error, int data)
+{
+ CharstringInterp::error(error, data);
+ _errh->error("%s", error_string().c_str());
+ return false;
+}
+
+bool
+CharstringSubrChecker::type1_command(int cmd)
+{
+ switch (cmd) {
+ case Cs::cReturn:
+ _returned = true;
+ return false;
+ default:
+ clear();
+ return true;
+ }
+}
+
+bool
+CharstringSubrChecker::check(const CharstringContext &g, ErrorHandler *errh)
+{
+ CharstringCheckerErrorHandler<CharstringSubrChecker> merrh(errh, this);
+ _errh = &merrh;
+ int old_errors = errh->nerrors();
+
+ _returned = false;
+
+ CharstringInterp::interpret(g);
+
+ if (!_returned)
+ _errh->error("subroutine does not return");
+ return errh->nerrors() == old_errors;
+}