diff --git a/pdf2htmlEX/CMakeLists.txt b/pdf2htmlEX/CMakeLists.txt
index 3852c22..b8e5008 100644
--- a/pdf2htmlEX/CMakeLists.txt
+++ b/pdf2htmlEX/CMakeLists.txt
@@ -149,6 +149,8 @@ set(PDF2HTMLEX_SRC ${PDF2HTMLEX_SRC}
src/util/unicode.cc
src/util/mingw.h
src/util/mingw.cc
+ src/util/SignalHandler.h
+ src/util/SignalHandler.cc
src/ArgParser.h
src/ArgParser.cc
src/Base64Stream.h
diff --git a/pdf2htmlEX/src/pdf2htmlEX.cc b/pdf2htmlEX/src/pdf2htmlEX.cc
index d08bc6c..9191489 100644
--- a/pdf2htmlEX/src/pdf2htmlEX.cc
+++ b/pdf2htmlEX/src/pdf2htmlEX.cc
@@ -25,6 +25,8 @@
#include "pdf2htmlEX-config.h"
+#include "util/SignalHandler.h"
+
#if ENABLE_SVG
#include
#endif
@@ -55,11 +57,15 @@ void show_usage_and_exit(const char * dummy = nullptr)
void show_version_and_exit(const char * dummy = nullptr)
{
+ const FFWVersionInfo* ffwVersionInfo = ffw_get_version_info();
+
cerr << "pdf2htmlEX version " << PDF2HTMLEX_VERSION << endl;
cerr << "Copyright 2012-2015 Lu Wang and other contributors" << endl;
cerr << "Libraries: " << endl;
cerr << " poppler " << POPPLER_VERSION << endl;
- cerr << " libfontforge " << ffw_get_version() << endl;
+ cerr << " libfontforge " << ffwVersionInfo->majorVersion << "." <<
+ ffwVersionInfo->minorVersion << "." << ffwVersionInfo->gitVersion << endl;
+ cerr << " libfontforge (date) " << ffwVersionInfo->versionDate << endl;
#if ENABLE_SVG
cerr << " cairo " << cairo_version_string() << endl;
#endif
@@ -394,6 +400,12 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
+ // setup the signal handler
+ setupSignalHandler(argc, (const char**)argv,
+ param.data_dir.c_str(),
+ param.poppler_data_dir.c_str(),
+ param.tmp_dir.c_str());
+
bool finished = false;
// read config file
globalParams = new GlobalParams(!param.poppler_data_dir.empty() ? param.poppler_data_dir.c_str() : NULL);
diff --git a/pdf2htmlEX/src/util/SignalHandler.cc b/pdf2htmlEX/src/util/SignalHandler.cc
new file mode 100644
index 0000000..c19eedc
--- /dev/null
+++ b/pdf2htmlEX/src/util/SignalHandler.cc
@@ -0,0 +1,220 @@
+/*
+ * SignalHandler.cc
+ *
+ * Created on: 2019-Nov-14
+ * Author: Stephen Gaito
+ */
+
+/**********
+
+This collection of basic ANSI-C functions implement a crude SIG-SEGV
+handler for when things go horribly wrong ;-(
+
+We implement them in as simple a maner as possible so that it will be as
+portable as possible and less likely to fall into a reentrant deadlock.
+
+At the moment the most critical SIG-SEGVs are happening inside the
+FontForge library. So we start by focusing upon adding more helpful
+messages when FontForge can't save a file for us.
+
+**********/
+
+
+#include
+#include
+#include
+#include
+#include
+
+#include "pdf2htmlEX-config.h"
+#include "util/ffw.h"
+#include
+#include
+
+const char* oopsMessage =
+ "\n"
+ "\n"
+ "Oops! Something went horribly wrong.... sorry!\n"
+ "\n";
+
+const char* ffwMessage_1 =
+ "I was in the middle of asking FontForge to ";
+
+const char* ffwMessage_2 =
+ " a font.\n"
+ "\n"
+ "I suspect that the problem is that FontForge is having trouble\n"
+ "working with one of the fonts embedded in your pdf file.\n"
+ "\n"
+ "The best way to verify this is to install FontForge and to try\n"
+ "loading and then (re)generating each font in the\n"
+ "\n"
+ " ";
+
+const char* ffwMessage_3 =
+ "\n"
+ "\n"
+ "directory. See:\n"
+ "\n"
+ " https://github.com/pdf2htmlEX/pdf2htmlEX/wiki/Troubleshooting-Crashes\n"
+ "\n"
+ "for details.\n"
+ "\n"
+ "If one of these fonts crashes FontForge, then it is certainly not a\n"
+ "pdf2htmlEX problem.... sorry.\n"
+ "\n"
+ "IF it *is* a FontForge problem then you have the following options:\n"
+ "\n"
+ " 1) You can send a copy of the font you found which crashed FontForge to\n"
+ " the FontForge developers and see if they can find the problem.\n"
+ " (Be warned FontForge is a complex application, so it might be\n"
+ " very hard for the developers to isolate your problem.... )\n"
+ "\n"
+ " 2) You can try re-creating your PDF with a different font.\n"
+ "\n"
+ " 3) Or you can do both of these things...\n"
+ "\n"
+ "IF you were not able to crash FontForge using the fonts in the above\n"
+ "directory... then and only then please raise an issue with the pdf2htmlEX\n"
+ "team... make sure you provide them with your pdf, as well as the following\n"
+ "details:\n";
+
+const char* noFfwMessage =
+ "Please raise an issue with the pdf2hmtlEX team so they can fix this...\n"
+ "\n"
+ "Please make sure you provide them with your pdf as well as the following\n"
+ "details:\n";
+
+const char* detailsHeader =
+ "\n"
+ "--------------------------------------------------------------------------\n"
+ "\n";
+
+const char* detailsBody = "no details recorded\n";
+
+const char* pdf2htmlEXTmpDir = NULL;
+const char* ffwAction = NULL;
+
+struct sigaction act;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-result"
+void signalHandler(int sigInt) {
+ write(STDERR_FILENO, oopsMessage, strlen(oopsMessage) );
+
+ if (ffwAction) {
+ write(STDERR_FILENO, ffwMessage_1, strlen(ffwMessage_1) );
+ write(STDERR_FILENO, ffwAction, strlen(ffwAction) );
+ write(STDERR_FILENO, ffwMessage_2, strlen(ffwMessage_2) );
+ write(STDERR_FILENO, pdf2htmlEXTmpDir, strlen(pdf2htmlEXTmpDir) );
+ write(STDERR_FILENO, ffwMessage_3, strlen(ffwMessage_3) );
+ } else {
+ write(STDERR_FILENO, noFfwMessage, strlen(noFfwMessage) );
+ }
+
+ write(STDERR_FILENO, detailsHeader, strlen(detailsHeader) );
+ write(STDERR_FILENO, detailsBody, strlen(detailsBody) );
+ exit(-1);
+
+}
+#pragma GCC diagnostic pop
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void ffwSetAction(const char* anAction) { ffwAction = anAction; }
+void ffwClearAction(const char* anAction) { ffwAction = NULL; }
+
+#ifdef __cplusplus
+}
+#endif
+
+void setupSignalHandler(
+ int argc, const char* argv[],
+ const char* data_dir,
+ const char* poppler_data_dir,
+ const char* tmp_dir) {
+ // THIS MUST BE CALLED AFTER ARGUMENT PARSING
+
+ // Start by setting up the messages
+ //
+ // Construct the command line information
+ std::string detailInfo;
+ detailInfo = "Command line:\n";
+ for (int i = 0 ; i < argc ; i++ ){
+ detailInfo = detailInfo + " " + std::to_string(i) + ": [" + argv[i] + "]\n" ;
+ }
+ detailInfo = detailInfo + "\n";
+
+ // Construct the version information
+ const pdf2htmlEX::FFWVersionInfo* ffwVersionInfo =
+ pdf2htmlEX::ffw_get_version_info();
+
+ detailInfo = detailInfo + "Version information:\n";
+ detailInfo = detailInfo + " pdf2htmlEX version " + pdf2htmlEX::PDF2HTMLEX_VERSION + "\n";
+ detailInfo = detailInfo + " Copyright 2012-2015 Lu Wang and other contributors\n";
+ detailInfo = detailInfo + "\n";
+ detailInfo = detailInfo + "Libraries:\n" ;
+ detailInfo = detailInfo + " poppler " + POPPLER_VERSION + "\n";
+ detailInfo = detailInfo + " libfontforge " + ffwVersionInfo->majorVersion + "." + ffwVersionInfo->minorVersion + "." + ffwVersionInfo->gitVersion + "\n";
+ detailInfo = detailInfo + " libfontforge (date) " + ffwVersionInfo->versionDate + "\n";
+#if ENABLE_SVG
+ detailInfo = detailInfo + " cairo " + cairo_version_string() + "\n";
+#endif
+ detailInfo = detailInfo + "\n";
+ detailInfo = detailInfo + "Default data-dir: " + data_dir + "\n";
+ detailInfo = detailInfo + "Default poppler-data-dir: " + poppler_data_dir + "\n";
+ detailInfo = detailInfo + "Default tmp-dir: " + tmp_dir + "\n";
+ detailInfo = detailInfo + "\n";
+ detailInfo = detailInfo + "Supported image formats:";
+#ifdef ENABLE_LIBPNG
+ detailInfo = detailInfo + " png";
+#endif
+#ifdef ENABLE_LIBJPEG
+ detailInfo = detailInfo + " jpg";
+#endif
+#if ENABLE_SVG
+ detailInfo = detailInfo + " svg";
+#endif
+ detailInfo = detailInfo + "\n\n";
+
+ detailsBody = strdup(detailInfo.c_str());
+
+ pdf2htmlEXTmpDir = strdup(tmp_dir);
+
+ // Now setup the signal handler
+ //
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = signalHandler;
+ //
+ sigaction(SIGILL, &act, NULL); // Illegal Instruction
+ sigaction(SIGFPE, &act, NULL); // Floating-point exception
+ sigaction(SIGSEGV, &act, NULL); // Invalid memory reference
+ sigaction(SIGBUS, &act, NULL); // Bus error (bad memory access)
+ sigaction(SIGSYS, &act, NULL); // Bad system call (SVr4)
+
+ // All done
+}
+
+
+/***
+int main(int argc, const char* argv[]) {
+
+ setupSignalHandler(argc, argv, "aTmpDir");
+
+ ffwSetAction("save");
+
+ for (int i = 0; i < 5; i++) {
+ printf("sleeping.... \n");
+ sleep(1);
+ }
+
+ int *foo = NULL;
+
+ *foo = 1;
+
+ printf("We should not reach here!\n");
+
+}
+***/
diff --git a/pdf2htmlEX/src/util/SignalHandler.h b/pdf2htmlEX/src/util/SignalHandler.h
new file mode 100644
index 0000000..d39b844
--- /dev/null
+++ b/pdf2htmlEX/src/util/SignalHandler.h
@@ -0,0 +1,21 @@
+#ifndef SIGNAL_HANDLER_H
+#define SIGNAL_HANDLER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void ffwSetAction(const char* anAction);
+void ffwClearAction(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+void setupSignalHandler(
+ int argc, const char* argv[],
+ const char* data_dir,
+ const char* poppler_data_dir,
+ const char* tmp_dir);
+
+#endif
diff --git a/pdf2htmlEX/src/util/ffw.c b/pdf2htmlEX/src/util/ffw.c
index c296f38..2101cde 100644
--- a/pdf2htmlEX/src/util/ffw.c
+++ b/pdf2htmlEX/src/util/ffw.c
@@ -16,6 +16,8 @@
#include
#include
+#include "SignalHandler.h"
+
#include "ffw.h"
#include "fontforge-2.0.20170731/autowidth.h"
#include "fontforge-2.0.20170731/bitmapchar.h"
@@ -66,6 +68,7 @@ static void dumb_post_error(const char * title, const char * error, ...) { }
void ffw_init(int debug)
{
+ ffwSetAction("initialize");
InitSimpleStuff();
if ( default_encoding==NULL )
default_encoding=FindOrMakeEncoding("ISO8859-1");
@@ -88,10 +91,12 @@ void ffw_init(int debug)
v.u.ival = 1;
SetPrefs("DetectDiagonalStems", &v, NULL);
}
+ ffwClearAction();
}
void ffw_finalize(void)
{
+ ffwSetAction("finalize");
while(enc_head)
{
Encoding * next = enc_head->next;
@@ -107,21 +112,36 @@ void ffw_finalize(void)
free(enc_head);
enc_head = next;
}
+ ffwClearAction();
}
-long ffw_get_version(void)
+// see: https://stackoverflow.com/a/2653351
+#define xstr(a) str(a)
+#define str(a) #a
+
+static FFWVersionInfo ffwVersionInfo;
+
+const FFWVersionInfo* ffw_get_version_info(void)
{
- return FONTFORGE_VERSIONDATE_RAW;
+ ffwVersionInfo.gitVersion = FONTFORGE_GIT_VERSION;
+ ffwVersionInfo.majorVersion = xstr(FONTFORGE_VERSION_MAJOR);
+ ffwVersionInfo.minorVersion = xstr(FONTFORGE_VERSION_MINOR);
+ ffwVersionInfo.versionDate = FONTFORGE_VERSIONDATE;
+
+ return &ffwVersionInfo;
}
void ffw_new_font()
{
+ ffwSetAction("create");
assert((cur_fv == NULL) && "Previous font is not destroyed");
cur_fv = FVAppend(_FontViewCreate(SplineFontNew()));
+ ffwClearAction();
}
void ffw_load_font(const char * filename)
{
+ ffwSetAction("load");
assert((cur_fv == NULL) && "Previous font is not destroyed");
char * _filename = strcopy(filename);
@@ -147,6 +167,7 @@ void ffw_load_font(const char * filename)
cur_fv->cidmaster->ascent = cur_fv->sf->ascent;
cur_fv->cidmaster->descent = cur_fv->sf->descent;
}
+ ffwClearAction();
}
/*
@@ -154,6 +175,7 @@ void ffw_load_font(const char * filename)
*/
void ffw_prepare_font(void)
{
+ ffwSetAction("prepare");
memset(cur_fv->selected, 1, cur_fv->map->enccount);
// remove kern
FVRemoveKerns(cur_fv);
@@ -185,10 +207,12 @@ void ffw_prepare_font(void)
*/
free(sf->fontname);
sf->fontname = strcopy("");
+ ffwClearAction();
}
void ffw_save(const char * filename)
{
+ ffwSetAction("save");
char * _filename = strcopy(filename);
char * _ = strcopy("");
@@ -200,11 +224,14 @@ void ffw_save(const char * filename)
if(!r)
err("Cannot save font to %s\n", filename);
+ ffwClearAction();
}
void ffw_close(void)
{
+ ffwSetAction("close");
FontViewClose(cur_fv);
cur_fv = NULL;
+ ffwClearAction();
}
static void ffw_do_reencode(Encoding * encoding, int force)
@@ -234,25 +261,32 @@ static void ffw_do_reencode(Encoding * encoding, int force)
void ffw_reencode_glyph_order(void)
{
+ ffwSetAction("re-encode the glyph order in");
ffw_do_reencode(original_enc, 0);
+ ffwClearAction();
}
void ffw_reencode_unicode_full(void)
{
+ ffwSetAction("re-encode to unicode");
ffw_do_reencode(unicodefull_enc, 0);
+ ffwClearAction();
}
void ffw_reencode(const char * encname, int force)
{
+ ffwSetAction("re-encode");
Encoding * enc = FindOrMakeEncoding(encname);
if(!enc)
err("Unknown encoding %s\n", encname);
ffw_do_reencode(enc, force);
+ ffwClearAction();
}
void ffw_reencode_raw(int32 * mapping, int mapping_len, int force)
{
+ ffwSetAction("re-encode (raw1)");
Encoding * enc = calloc(1, sizeof(Encoding));
enc->only_1byte = enc->has_1byte = true;
@@ -273,10 +307,12 @@ void ffw_reencode_raw(int32 * mapping, int mapping_len, int force)
enc_head = enc;
ffw_do_reencode(enc, force);
+ ffwClearAction();
}
void ffw_reencode_raw2(const char ** mapping, int mapping_len, int force)
{
+ ffwSetAction("re-encode (raw2)");
Encoding * enc = calloc(1, sizeof(Encoding));
enc->enc_name = strcopy("");
enc->char_cnt = mapping_len;
@@ -300,6 +336,7 @@ void ffw_reencode_raw2(const char ** mapping, int mapping_len, int force)
enc_head = enc;
ffw_do_reencode(enc, force);
+ ffwClearAction();
}
void ffw_cidflatten(void)
@@ -309,7 +346,9 @@ void ffw_cidflatten(void)
fprintf(stderr, "Cannot flatten a non-CID font\n");
return;
}
+ ffwSetAction("flatten the cid in");
SFFlatten(cur_fv->sf->cidmaster);
+ ffwClearAction();
}
/*
@@ -318,6 +357,7 @@ void ffw_cidflatten(void)
*/
void ffw_add_empty_char(int32_t unicode, int width)
{
+ ffwSetAction("add an empty character to");
SplineChar * sc = SFMakeChar(cur_fv->sf, cur_fv->map, cur_fv->map->enccount);
char buffer[400];
SCSetMetaData(sc,
@@ -325,22 +365,29 @@ void ffw_add_empty_char(int32_t unicode, int width)
cur_fv->sf->uni_interp, cur_fv->sf->for_new_glyphs)),
unicode, sc->comment);
SCSynchronizeWidth(sc, width, sc->width, cur_fv);
+ ffwClearAction();
}
int ffw_get_em_size(void)
{
- return cur_fv->sf->ascent + cur_fv->sf->descent;
+ ffwSetAction("get the em size of");
+ int emSize = cur_fv->sf->ascent + cur_fv->sf->descent;
+ ffwClearAction();
+ return emSize;
}
void ffw_fix_metric()
{
+ ffwSetAction("fix the metric of");
double ascent, descent;
ffw_get_metric(&ascent, &descent);
ffw_set_metric(ascent, descent);
+ ffwClearAction();
}
void ffw_get_metric(double * ascent, double * descent)
{
+ ffwSetAction("get the metric of");
SplineFont * sf = cur_fv->sf;
DBounds bb;
@@ -357,10 +404,12 @@ void ffw_get_metric(double * ascent, double * descent)
{
*ascent = *descent = 0;
}
+ ffwClearAction();
}
void ffw_set_metric(double ascent, double descent)
{
+ ffwSetAction("set the metric of");
SplineFont * sf = cur_fv->sf;
struct pfminfo * info = &sf->pfminfo;
@@ -402,6 +451,7 @@ void ffw_set_metric(double ascent, double descent)
info->os2_typolinegap = 0;
info->linegap = 0;
+ ffwClearAction();
}
/*
@@ -410,6 +460,7 @@ void ffw_set_metric(double ascent, double descent)
void ffw_set_widths(int * width_list, int mapping_len,
int stretch_narrow, int squeeze_wide)
{
+ ffwSetAction("set the widths of");
SplineFont * sf = cur_fv->sf;
if(sf->onlybitmaps
@@ -453,13 +504,17 @@ void ffw_set_widths(int * width_list, int mapping_len,
SCSynchronizeWidth(sc, width_list[i], sc->width, cur_fv);
}
+ ffwClearAction();
}
void ffw_import_svg_glyph(int code, const char * filename, double ox, double oy, double width)
{
+ ffwSetAction("import the glyphs from");
int enc = SFFindSlot(cur_fv->sf, cur_fv->map, code, "");
- if(enc == -1)
+ if(enc == -1) {
+ ffwClearAction();
return;
+ }
SplineChar * sc = SFMakeChar(cur_fv->sf, cur_fv->map, enc);
@@ -483,10 +538,12 @@ void ffw_import_svg_glyph(int code, const char * filename, double ox, double oy,
SCSynchronizeWidth(sc, floor(width * (a+d) + 0.5), sc->width, cur_fv);
}
+ ffwClearAction();
}
void ffw_auto_hint(void)
{
+ ffwSetAction("automatically hint");
// convert to quadratic
if(!(cur_fv->sf->layers[ly_fore].order2))
{
@@ -496,11 +553,14 @@ void ffw_auto_hint(void)
memset(cur_fv->selected, 1, cur_fv->map->enccount);
FVAutoHint(cur_fv);
FVAutoInstr(cur_fv);
+ ffwClearAction();
}
void ffw_override_fstype(void)
{
+ ffwSetAction("override the fstype of");
*(int16 *)(&cur_fv->sf->pfminfo.fstype) = 0;
cur_fv->sf->pfminfo.pfmset = true;
cur_fv->sf->changed = true;
+ ffwClearAction();
}
diff --git a/pdf2htmlEX/src/util/ffw.h b/pdf2htmlEX/src/util/ffw.h
index 106310a..5ce70e9 100644
--- a/pdf2htmlEX/src/util/ffw.h
+++ b/pdf2htmlEX/src/util/ffw.h
@@ -23,7 +23,15 @@ extern "C" {
// global
void ffw_init(int debug);
void ffw_finalize(void);
-long ffw_get_version(void);
+
+typedef struct ffw_version_info {
+ const char* gitVersion;
+ const char* majorVersion;
+ const char* minorVersion;
+ const char* versionDate;
+} FFWVersionInfo ;
+
+const FFWVersionInfo* ffw_get_version_info(void);
////////////////////////
// load & save