Commit 6603a35c authored by Nathan Lee's avatar Nathan Lee

Crashfix on opening pdf if page fails to load

Can not assume pdf page will exist.
Also no longer creates a blank document if the
poppler/cairo import fails.

Address malcrafted PDFs found by Carlos Ramirez
#1632

(cherry-picked from 5d3a849a)
parent d6d20de3
Pipeline #161432462 passed with stages
in 114 minutes and 1 second
......@@ -32,36 +32,32 @@
#include <poppler/glib/poppler-page.h>
#endif
#include <gdkmm/general.h>
#include <glibmm/convert.h>
#include <glibmm/i18n.h>
#include <glibmm/miscutils.h>
#include <gtk/gtk.h>
#include <gtkmm/checkbutton.h>
#include <gtkmm/comboboxtext.h>
#include <gtkmm/drawingarea.h>
#include <gtkmm/frame.h>
#include <gtkmm/radiobutton.h>
#include <gtkmm/scale.h>
#include <glibmm/convert.h>
#include <glibmm/miscutils.h>
#include <gtk/gtk.h>
#include <glibmm/i18n.h>
#include "ui/dialog-events.h"
#include "ui/widget/spinbutton.h"
#include "ui/widget/frame.h"
#include "extension/system.h"
#include "extension/input.h"
#include "svg-builder.h"
#include "pdf-parser.h"
#include <utility>
#include "document-undo.h"
#include "extension/input.h"
#include "extension/system.h"
#include "inkscape.h"
#include "util/units.h"
#include "object/sp-root.h"
#include "pdf-parser.h"
#include "svg-builder.h"
#include "ui/dialog-events.h"
#include "ui/widget/frame.h"
#include "ui/widget/spinbutton.h"
#include "util/units.h"
#include <gdkmm/general.h>
namespace {
......@@ -96,12 +92,13 @@ static const gchar * crop_setting_choices[] = {
N_("art box")
};
PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
PdfImportDialog::PdfImportDialog(std::shared_ptr<PDFDoc> doc, const gchar */*uri*/)
: _pdf_doc(std::move(doc))
{
assert(_pdf_doc);
#ifdef HAVE_POPPLER_CAIRO
_poppler_doc = NULL;
#endif // HAVE_POPPLER_CAIRO
_pdf_doc = doc;
cancelbutton = Gtk::manage(new Gtk::Button(_("_Cancel"), true));
okbutton = Gtk::manage(new Gtk::Button(_("_OK"), true));
_labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:")));
......@@ -577,6 +574,7 @@ bool PdfImportDialog::_onDraw(const Cairo::RefPtr<Cairo::Context>& cr) {
void PdfImportDialog::_setPreviewPage(int page) {
_previewed_page = _pdf_doc->getCatalog()->getPage(page);
g_return_if_fail(_previewed_page);
// Try to get a thumbnail from the PDF if possible
if (!_render_thumb) {
if (_thumb_data) {
......@@ -688,13 +686,15 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
}
// Open the file using poppler
// PDFDoc is from poppler. PDFDoc is used for preview and for native import.
std::shared_ptr<PDFDoc> pdf_doc;
#ifndef _WIN32
// poppler does not use glib g_open. So on win32 we must use unicode call. code was copied from
// glib gstdio.c
GooString *filename_goo = new GooString(uri);
PDFDoc *pdf_doc = new PDFDoc(filename_goo, nullptr, nullptr, nullptr); // TODO: Could ask for password
pdf_doc = std::make_shared<PDFDoc>(filename_goo, nullptr, nullptr, nullptr); // TODO: Could ask for password
//delete filename_goo;
#else
wchar_t *wfilename = reinterpret_cast<wchar_t*>(g_utf8_to_utf16 (uri, -1, NULL, NULL, NULL));
......@@ -703,13 +703,12 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
return NULL;
}
PDFDoc *pdf_doc = new PDFDoc(wfilename, wcslen(wfilename), NULL, NULL, NULL); // TODO: Could ask for password
pdf_doc = std::make_shared<PDFDoc>(wfilename, wcslen(wfilename), nullptr, nullptr, nullptr); // TODO: Could ask for password
g_free (wfilename);
#endif
if (!pdf_doc->isOk()) {
int error = pdf_doc->getErrorCode();
delete pdf_doc;
if (error == errEncrypted) {
g_message("Document is encrypted.");
} else if (error == errOpenFile) {
......@@ -737,12 +736,11 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
return nullptr;
}
PdfImportDialog *dlg = nullptr;
std::unique_ptr<PdfImportDialog> dlg;
if (INKSCAPE.use_gui()) {
dlg = new PdfImportDialog(pdf_doc, uri);
dlg.reset(new PdfImportDialog(pdf_doc, uri));
if (!dlg->showDialog()) {
delete dlg;
delete pdf_doc;
throw Input::open_cancelled();
}
}
......@@ -763,12 +761,25 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
#endif
}
// Create Inkscape document from file
SPDocument *doc = nullptr;
bool saved = false;
if(!is_importvia_poppler)
{
// native importer
doc = SPDocument::createNewDoc(nullptr, TRUE, TRUE);
// Check page exists
Catalog *catalog = pdf_doc->getCatalog();
int const num_pages = catalog->getNumPages();
sanitize_page_number(page_num, num_pages);
Page *page = catalog->getPage(page_num);
if (!page) {
std::cerr << "PDFInput::open: error opening page " << page_num << std::endl;
return nullptr;
}
// Create document
doc = SPDocument::createNewDoc(nullptr, true, true);
saved = DocumentUndo::getUndoSensitive(doc);
DocumentUndo::setUndoSensitive(doc, false); // No need to undo in this temporary document
......@@ -790,11 +801,6 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
double crop_setting = -1.0;
sp_repr_get_double(prefs, "cropTo", &crop_setting);
Catalog *catalog = pdf_doc->getCatalog();
int const num_pages = catalog->getNumPages();
sanitize_page_number(page_num, num_pages);
Page *page = catalog->getPage(page_num);
if ( crop_setting >= 0.0 ) { // Do page clipping
int crop_choice = (int)crop_setting;
switch (crop_choice) {
......@@ -868,18 +874,21 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
/// @todo handle password
/// @todo check if win32 unicode needs special attention
PopplerDocument* document = poppler_document_new_from_file(full_uri.c_str(), NULL, &error);
PopplerPage* page = nullptr;
if(error != NULL) {
std::cerr << "PDFInput::open: error opening document: " << full_uri << std::endl;
g_error_free (error);
}
if (document != NULL)
{
double width, height;
if (document) {
int const num_pages = poppler_document_get_n_pages(document);
sanitize_page_number(page_num, num_pages);
PopplerPage* page = poppler_document_get_page(document, page_num - 1);
page = poppler_document_get_page(document, page_num - 1);
}
if (page) {
double width, height;
poppler_page_get_size(page, &width, &height);
Glib::ustring output;
......@@ -901,25 +910,27 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
cairo_surface_destroy(surface);
doc = SPDocument::createNewDocFromMem(output.c_str(), output.length(), TRUE);
// Cleanup
// delete output;
g_object_unref(G_OBJECT(page));
} else if (document) {
std::cerr << "PDFInput::open: error opening page " << page_num << " of document: " << full_uri << std::endl;
}
// Cleanup
if (document) {
g_object_unref(G_OBJECT(document));
if (page) {
g_object_unref(G_OBJECT(page));
}
}
else
{
doc = SPDocument::createNewDoc(NULL, TRUE, TRUE); // fallback create empty document
if (!doc) {
return nullptr;
}
saved = DocumentUndo::getUndoSensitive(doc);
DocumentUndo::setUndoSensitive(doc, false); // No need to undo in this temporary document
#endif
}
// Cleanup
delete pdf_doc;
delete dlg;
// Set viewBox if it doesn't exist
if (!doc->getRoot()->viewBox_set) {
doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDisplayUnit()), doc->getHeight().value(doc->getDisplayUnit())));
......
......@@ -64,7 +64,7 @@ namespace Internal {
class PdfImportDialog : public Gtk::Dialog
{
public:
PdfImportDialog(PDFDoc *doc, const gchar *uri);
PdfImportDialog(std::shared_ptr<PDFDoc> doc, const gchar *uri);
~PdfImportDialog() override;
bool showDialog();
......@@ -120,7 +120,7 @@ private:
class Gtk::DrawingArea * _previewArea;
class Gtk::HBox * hbox1;
PDFDoc *_pdf_doc; // Document to be imported
std::shared_ptr<PDFDoc> _pdf_doc; // Document to be imported
int _current_page; // Current selected page
Page *_previewed_page; // Currently previewed page
unsigned char *_thumb_data; // Thumbnail image data
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment