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

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