Merge remote branch 'hwhw/master'

* hwhw/master:
  Password input, handling for broken documents
  factored pages count out, better error and password handling
  factored pages counter out of document struct
pull/2/merge
traycold 12 years ago
commit fd6c6dbe60

@ -31,7 +31,6 @@
typedef struct DjvuDocument { typedef struct DjvuDocument {
ddjvu_context_t *context; ddjvu_context_t *context;
ddjvu_document_t *doc_ref; ddjvu_document_t *doc_ref;
int pages;
} DjvuDocument; } DjvuDocument;
typedef struct DjvuPage { typedef struct DjvuPage {
@ -90,7 +89,6 @@ static int openDocument(lua_State *L) {
return luaL_error(L, "cannot open DJVU file <%s>", filename); return luaL_error(L, "cannot open DJVU file <%s>", filename);
} }
doc->pages = ddjvu_document_get_pagenum(doc->doc_ref);
return 1; return 1;
} }
@ -109,7 +107,7 @@ static int closeDocument(lua_State *L) {
static int getNumberOfPages(lua_State *L) { static int getNumberOfPages(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); 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; return 1;
} }
@ -175,8 +173,8 @@ static int openPage(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
int pageno = luaL_checkint(L, 2); int pageno = luaL_checkint(L, 2);
if(pageno < 1 || 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, doc->pages); 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)); DjvuPage *page = (DjvuPage*) lua_newuserdata(L, sizeof(DjvuPage));

@ -5,6 +5,10 @@ DJVUReader = UniReader:new{}
-- open a DJVU file and its settings store -- open a DJVU file and its settings store
-- DJVU does not support password yet -- DJVU does not support password yet
function DJVUReader:open(filename) function DJVUReader:open(filename)
self.doc = djvu.openDocument(filename) local ok
return self:loadSettings(filename) 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 end

62
pdf.c

@ -24,7 +24,6 @@
typedef struct PdfDocument { typedef struct PdfDocument {
fz_document *xref; fz_document *xref;
fz_context *context; fz_context *context;
int pages;
} PdfDocument; } PdfDocument;
typedef struct PdfPage { typedef struct PdfPage {
@ -38,8 +37,7 @@ typedef struct PdfPage {
static int openDocument(lua_State *L) { static int openDocument(lua_State *L) {
char *filename = strdup(luaL_checkstring(L, 1)); char *filename = strdup(luaL_checkstring(L, 1));
char *password = strdup(luaL_checkstring(L, 2)); int cachesize = luaL_optint(L, 2, 64 << 20); // 64 MB limit default
int cachesize = luaL_optint(L, 3, 64 << 20); // 64 MB limit default
PdfDocument *doc = (PdfDocument*) lua_newuserdata(L, sizeof(PdfDocument)); PdfDocument *doc = (PdfDocument*) lua_newuserdata(L, sizeof(PdfDocument));
@ -53,19 +51,28 @@ static int openDocument(lua_State *L) {
} }
fz_catch(doc->context) { fz_catch(doc->context) {
free(filename); free(filename);
free(password); return luaL_error(L, "cannot open PDF file");
return luaL_error(L, "cannot open PDF file <%s>", filename);
} }
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); 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); free(password);
return 1; return 1;
} }
@ -85,7 +92,12 @@ static int closeDocument(lua_State *L) {
static int getNumberOfPages(lua_State *L) { static int getNumberOfPages(lua_State *L) {
PdfDocument *doc = (PdfDocument*) luaL_checkudata(L, 1, "pdfdocument"); 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; return 1;
} }
@ -148,24 +160,24 @@ static int openPage(lua_State *L) {
int pageno = luaL_checkint(L, 2); int pageno = luaL_checkint(L, 2);
if(pageno < 1 || pageno > doc->pages) { fz_try(doc->context) {
return luaL_error(L, "cannot open page #%d, out of range (1-%d)", pageno, doc->pages); 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"); luaL_getmetatable(L, "pdfpage");
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
fz_try(doc->context) {
page->page = fz_load_page(doc->xref, pageno - 1); page->page = fz_load_page(doc->xref, pageno - 1);
page->doc = doc;
} }
fz_catch(doc->context) { fz_catch(doc->context) {
return luaL_error(L, "cannot open page #%d", pageno); return luaL_error(L, "cannot open page #%d", pageno);
} }
page->doc = doc;
return 1; return 1;
} }
@ -288,6 +300,8 @@ static const struct luaL_Reg pdf_func[] = {
}; };
static const struct luaL_Reg pdfdocument_meth[] = { static const struct luaL_Reg pdfdocument_meth[] = {
{"needsPassword", needsPassword},
{"authenticatePassword", authenticatePassword},
{"openPage", openPage}, {"openPage", openPage},
{"getPages", getNumberOfPages}, {"getPages", getNumberOfPages},
{"getTOC", getTableOfContent}, {"getTOC", getTableOfContent},

@ -1,9 +1,32 @@
require "unireader" require "unireader"
require "inputbox"
PDFReader = UniReader:new{} PDFReader = UniReader:new{}
-- open a PDF file and its settings store -- open a PDF file and its settings store
function PDFReader:open(filename, password) function PDFReader:open(filename)
self.doc = pdf.openDocument(filename, password or "") -- muPDF manages its own cache, set second parameter
return self:loadSettings(filename) -- 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 end

@ -37,21 +37,25 @@ longopts = {
function openFile(filename) function openFile(filename)
local file_type = string.lower(string.match(filename, ".+%.([^.]+)")) local file_type = string.lower(string.match(filename, ".+%.([^.]+)"))
local reader = nil
if file_type == "djvu" then if file_type == "djvu" then
if DJVUReader:open(filename) then reader = DJVUReader
page_num = DJVUReader.settings:readsetting("last_page") or 1
DJVUReader:goto(tonumber(page_num))
reader_settings:savesetting("lastfile", filename)
return DJVUReader:inputloop()
end
elseif file_type == "pdf" or file_type == "xps" or file_type == "cbz" then elseif file_type == "pdf" or file_type == "xps" or file_type == "cbz" then
if PDFReader:open(filename,"") then -- TODO: query for password reader = PDFReader
page_num = PDFReader.settings:readsetting("last_page") or 1 end
PDFReader:goto(tonumber(page_num)) 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) reader_settings:savesetting("lastfile", filename)
return PDFReader:inputloop() return reader:inputloop()
else
-- TODO: error handling
end end
end end
return true -- on failed attempts, we signal to keep running
end end
function showusage() function showusage()

@ -181,7 +181,11 @@ function UniReader:draworcache(no, preCache)
-- #4 goal: we render next page, too. (TODO) -- #4 goal: we render next page, too. (TODO)
-- ideally, this should be factored out and only be called when needed (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) local dc = self:setzoom(page)
-- offset_x_in_page & offset_y_in_page is the offset within zoomed page -- offset_x_in_page & offset_y_in_page is the offset within zoomed page
@ -439,6 +443,9 @@ end
-- render and blit a page -- render and blit a page
function UniReader:show(no) function UniReader:show(no)
local pagehash, offset_x, offset_y = self:draworcache(no) local pagehash, offset_x, offset_y = self:draworcache(no)
if not pagehash then
return
end
self.pagehash = pagehash self.pagehash = pagehash
local bb = self.cache[pagehash].bb local bb = self.cache[pagehash].bb
local dest_x = 0 local dest_x = 0

Loading…
Cancel
Save