From 87ec4bbf6b8276c2cc5399291a70234156a8157e Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 20 Mar 2012 00:03:09 +0100 Subject: [PATCH 1/3] factored pages counter out of document struct --- djvu.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/djvu.c b/djvu.c index 43ed4d28c..090d625a3 100644 --- a/djvu.c +++ b/djvu.c @@ -31,7 +31,6 @@ typedef struct DjvuDocument { ddjvu_context_t *context; ddjvu_document_t *doc_ref; - int pages; } DjvuDocument; typedef struct DjvuPage { @@ -90,7 +89,6 @@ static int openDocument(lua_State *L) { return luaL_error(L, "cannot open DJVU file <%s>", filename); } - doc->pages = ddjvu_document_get_pagenum(doc->doc_ref); return 1; } @@ -109,7 +107,7 @@ static int closeDocument(lua_State *L) { static int getNumberOfPages(lua_State *L) { DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); - lua_pushinteger(L, doc->pages); + lua_pushinteger(L, ddjvu_document_get_pagenum(doc->doc_ref)); return 1; } @@ -175,8 +173,8 @@ static int openPage(lua_State *L) { DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); int pageno = luaL_checkint(L, 2); - if(pageno < 1 || pageno > doc->pages) { - return luaL_error(L, "cannot open page #%d, out of range (1-%d)", pageno, doc->pages); + if(pageno < 1 || pageno > ddjvu_document_get_pagenum(doc->doc_ref)) { + return luaL_error(L, "cannot open page #%d, out of range (1-%d)", pageno, ddjvu_document_get_pagenum(doc->doc_ref)); } DjvuPage *page = (DjvuPage*) lua_newuserdata(L, sizeof(DjvuPage)); From b037208fb10cfe3d8c929a7088fc57bfcdf46d58 Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 20 Mar 2012 00:03:35 +0100 Subject: [PATCH 2/3] factored pages count out, better error and password handling --- pdf.c | 62 ++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/pdf.c b/pdf.c index 9f4935420..b335d65c7 100644 --- a/pdf.c +++ b/pdf.c @@ -24,7 +24,6 @@ typedef struct PdfDocument { fz_document *xref; fz_context *context; - int pages; } PdfDocument; typedef struct PdfPage { @@ -38,8 +37,7 @@ typedef struct PdfPage { static int openDocument(lua_State *L) { char *filename = strdup(luaL_checkstring(L, 1)); - char *password = strdup(luaL_checkstring(L, 2)); - int cachesize = luaL_optint(L, 3, 64 << 20); // 64 MB limit default + int cachesize = luaL_optint(L, 2, 64 << 20); // 64 MB limit default PdfDocument *doc = (PdfDocument*) lua_newuserdata(L, sizeof(PdfDocument)); @@ -53,19 +51,28 @@ static int openDocument(lua_State *L) { } fz_catch(doc->context) { free(filename); - free(password); - return luaL_error(L, "cannot open PDF file <%s>", filename); + return luaL_error(L, "cannot open PDF file"); } - if(fz_needs_password(doc->xref)) { - if (!fz_authenticate_password(doc->xref, password)) { - free(filename); - free(password); - return luaL_error(L, "cannot authenticate"); - } - } - doc->pages = fz_count_pages(doc->xref); free(filename); + return 1; +} + +static int needsPassword(lua_State *L) { + PdfDocument *doc = (PdfDocument*) luaL_checkudata(L, 1, "pdfdocument"); + lua_pushboolean(L, fz_needs_password(doc->xref)); + return 1; +} + +static int authenticatePassword(lua_State *L) { + PdfDocument *doc = (PdfDocument*) luaL_checkudata(L, 1, "pdfdocument"); + char *password = strdup(luaL_checkstring(L, 2)); + + if (!fz_authenticate_password(doc->xref, password)) { + lua_pushboolean(L, 0); + } else { + lua_pushboolean(L, 1); + } free(password); return 1; } @@ -85,7 +92,12 @@ static int closeDocument(lua_State *L) { static int getNumberOfPages(lua_State *L) { PdfDocument *doc = (PdfDocument*) luaL_checkudata(L, 1, "pdfdocument"); - lua_pushinteger(L, doc->pages); + fz_try(doc->context) { + lua_pushinteger(L, fz_count_pages(doc->xref)); + } + fz_catch(doc->context) { + return luaL_error(L, "cannot access page tree"); + } return 1; } @@ -148,24 +160,24 @@ static int openPage(lua_State *L) { int pageno = luaL_checkint(L, 2); - if(pageno < 1 || pageno > doc->pages) { - return luaL_error(L, "cannot open page #%d, out of range (1-%d)", pageno, doc->pages); - } + fz_try(doc->context) { + if(pageno < 1 || pageno > fz_count_pages(doc->xref)) { + return luaL_error(L, "cannot open page #%d, out of range (1-%d)", + pageno, fz_count_pages(doc->xref)); + } - PdfPage *page = (PdfPage*) lua_newuserdata(L, sizeof(PdfPage)); + PdfPage *page = (PdfPage*) lua_newuserdata(L, sizeof(PdfPage)); - luaL_getmetatable(L, "pdfpage"); - lua_setmetatable(L, -2); + luaL_getmetatable(L, "pdfpage"); + lua_setmetatable(L, -2); - fz_try(doc->context) { page->page = fz_load_page(doc->xref, pageno - 1); + + page->doc = doc; } fz_catch(doc->context) { return luaL_error(L, "cannot open page #%d", pageno); } - - page->doc = doc; - return 1; } @@ -288,6 +300,8 @@ static const struct luaL_Reg pdf_func[] = { }; static const struct luaL_Reg pdfdocument_meth[] = { + {"needsPassword", needsPassword}, + {"authenticatePassword", authenticatePassword}, {"openPage", openPage}, {"getPages", getNumberOfPages}, {"getTOC", getTableOfContent}, From 7e3e38be62dc88a7f9a64d5d4facfa18382d91c0 Mon Sep 17 00:00:00 2001 From: HW Date: Tue, 20 Mar 2012 00:10:19 +0100 Subject: [PATCH 3/3] Password input, handling for broken documents --- djvureader.lua | 8 ++++++-- pdfreader.lua | 29 ++++++++++++++++++++++++++--- reader.lua | 24 ++++++++++++++---------- unireader.lua | 9 ++++++++- 4 files changed, 54 insertions(+), 16 deletions(-) diff --git a/djvureader.lua b/djvureader.lua index 1b4b37697..0582073b9 100644 --- a/djvureader.lua +++ b/djvureader.lua @@ -5,6 +5,10 @@ DJVUReader = UniReader:new{} -- open a DJVU file and its settings store -- DJVU does not support password yet function DJVUReader:open(filename) - self.doc = djvu.openDocument(filename) - return self:loadSettings(filename) + local ok + ok, self.doc = pcall(djvu.openDocument, filename) + if not ok then + return ok, self.doc -- this will be the error message instead + end + return ok end diff --git a/pdfreader.lua b/pdfreader.lua index 2af16f1cb..ec4e1a105 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -1,9 +1,32 @@ require "unireader" +require "inputbox" PDFReader = UniReader:new{} -- open a PDF file and its settings store -function PDFReader:open(filename, password) - self.doc = pdf.openDocument(filename, password or "") - return self:loadSettings(filename) +function PDFReader:open(filename) + -- muPDF manages its own cache, set second parameter + -- to the maximum size you want it to grow + local ok + ok, self.doc = pcall(pdf.openDocument, filename, 64*1024*1024) + if not ok then + return false, self.doc -- will contain error message + end + if self.doc:needsPassword() then + local password = InputBox:input(height-100, 100, "Pass:") + if not password or not self.doc:authenticatePassword(password) then + self.doc:close() + self.doc = nil + return false, "wrong or missing password" + end + -- password wrong or not entered + end + local ok, err = pcall(self.doc.getPages, self.doc) + if not ok then + -- for PDFs, they might trigger errors later when accessing page tree + self.doc:close() + self.doc = nil + return false, "damaged page tree" + end + return true end diff --git a/reader.lua b/reader.lua index 83cc0bb1d..7afefa90f 100755 --- a/reader.lua +++ b/reader.lua @@ -35,21 +35,25 @@ longopts = { function openFile(filename) local file_type = string.lower(string.match(filename, ".+%.([^.]+)")) + local reader = nil if file_type == "djvu" then - if DJVUReader:open(filename) then - page_num = DJVUReader.settings:readsetting("last_page") or 1 - DJVUReader:goto(tonumber(page_num)) - reader_settings:savesetting("lastfile", filename) - return DJVUReader:inputloop() - end + reader = DJVUReader elseif file_type == "pdf" or file_type == "xps" or file_type == "cbz" then - if PDFReader:open(filename,"") then -- TODO: query for password - page_num = PDFReader.settings:readsetting("last_page") or 1 - PDFReader:goto(tonumber(page_num)) + reader = PDFReader + end + if reader then + local ok, err = reader:open(filename) + if ok then + reader:loadSettings(filename) + page_num = reader.settings:readsetting("last_page") or 1 + reader:goto(tonumber(page_num)) reader_settings:savesetting("lastfile", filename) - return PDFReader:inputloop() + return reader:inputloop() + else + -- TODO: error handling end end + return true -- on failed attempts, we signal to keep running end function showusage() diff --git a/unireader.lua b/unireader.lua index 27251a486..b738197a2 100644 --- a/unireader.lua +++ b/unireader.lua @@ -175,7 +175,11 @@ function UniReader:draworcache(no, preCache) -- #4 goal: we render next page, too. (TODO) -- ideally, this should be factored out and only be called when needed (TODO) - local page = self.doc:openPage(no) + local ok, page = pcall(self.doc.openPage, self.doc, no) + if not ok then + -- TODO: error handling + return nil + end local dc = self:setzoom(page) -- offset_x_in_page & offset_y_in_page is the offset within zoomed page @@ -433,6 +437,9 @@ end -- render and blit a page function UniReader:show(no) local pagehash, offset_x, offset_y = self:draworcache(no) + if not pagehash then + return + end self.pagehash = pagehash local bb = self.cache[pagehash].bb local dest_x = 0