mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Merge pull request #1667 from chrox/fixes_for_stable_release
add support for password protected zip/cbz documents
This commit is contained in:
@@ -46,6 +46,7 @@ install:
|
||||
- cp /etc/luarocks/config.lua $HOME/.luarocks/config.lua
|
||||
- echo "wrap_bin_scripts = false" >> $HOME/.luarocks/config.lua
|
||||
- travis_retry luarocks --local install lua_cliargs
|
||||
- travis_retry luarocks --local install ansicolors
|
||||
- travis_retry luarocks --local install busted
|
||||
#- travis_retry luarocks --local install busted 1.11.1-1
|
||||
#- mv -f $HOME/.luarocks/bin/busted_bootstrap $HOME/.luarocks/bin/busted
|
||||
|
||||
5
Makefile
5
Makefile
@@ -102,14 +102,14 @@ $(INSTALL_DIR)/koreader/.luacov:
|
||||
ln -sf ../../.luacov $(INSTALL_DIR)/koreader
|
||||
|
||||
testfront: $(INSTALL_DIR)/koreader/.busted
|
||||
cd $(INSTALL_DIR)/koreader && ./luajit $(shell which busted) --exclude-tags=notest
|
||||
cd $(INSTALL_DIR)/koreader && ./luajit $(shell which busted) -o verbose_print --exclude-tags=notest
|
||||
|
||||
test:
|
||||
$(MAKE) -C $(KOR_BASE) test
|
||||
$(MAKE) testfront
|
||||
|
||||
coverage: $(INSTALL_DIR)/koreader/.luacov
|
||||
cd $(INSTALL_DIR)/koreader && ./luajit $(shell which busted) --coverage --exclude-tags=nocov
|
||||
cd $(INSTALL_DIR)/koreader && ./luajit $(shell which busted) -o verbose_print --coverage --exclude-tags=nocov
|
||||
# coverage report summary
|
||||
cd $(INSTALL_DIR)/koreader && tail -n \
|
||||
+$$(($$(grep -nm1 Summary luacov.report.out|cut -d: -f1)-1)) \
|
||||
@@ -241,6 +241,7 @@ utupdate: all
|
||||
ln -sf ../../$(UBUNTUTOUCH_DIR)/koreader.sh $(INSTALL_DIR)/koreader
|
||||
ln -sf ../../$(UBUNTUTOUCH_DIR)/manifest.json $(INSTALL_DIR)/koreader
|
||||
ln -sf ../../$(UBUNTUTOUCH_DIR)/koreader.apparmor $(INSTALL_DIR)/koreader
|
||||
ln -sf ../../$(UBUNTUTOUCH_DIR)/koreader.apparmor.openstore $(INSTALL_DIR)/koreader
|
||||
ln -sf ../../$(UBUNTUTOUCH_DIR)/koreader.desktop $(INSTALL_DIR)/koreader
|
||||
ln -sf ../../$(UBUNTUTOUCH_DIR)/koreader.png $(INSTALL_DIR)/koreader
|
||||
ln -sf ../../../$(UBUNTUTOUCH_SDL_DIR)/lib/arm-linux-gnueabihf/libSDL2.so $(INSTALL_DIR)/koreader/libs
|
||||
|
||||
32
README.md
32
README.md
@@ -4,12 +4,12 @@
|
||||
KOReader
|
||||
========
|
||||
|
||||
[](https://gitter.im/koreader/koreader?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[![Join the chat][gitter-badge]][gitter-link]
|
||||
|
||||
KOReader is a document viewer application, originally created for Kindle
|
||||
e-ink readers. It currently runs on Kindle 5 (Touch), Kindle Paperwhite,
|
||||
Kobo, PocketBook and Android (2.3+) devices. Developers can also run Koreader emulator
|
||||
for development purpose on desktop PC with Linux or Windows operating system.
|
||||
e-ink readers. It currently runs on Kindle, Kobo, PocketBook, Ubuntu Touch
|
||||
and Android (2.3+) devices. Developers can also run Koreader emulator
|
||||
for development purpose on desktop PC with Linux and Windows operating system.
|
||||
|
||||
Main features for users
|
||||
-----------------------
|
||||
@@ -67,7 +67,7 @@ These instructions for how to get and compile the source are intended for a Linu
|
||||
OS. Windows users are suggested to develop in a [Linux VM][linux-vm] or use Wubi.
|
||||
|
||||
To get and compile the source you must have `patch`, `wget`, `unzip`, `git`,
|
||||
`subversion`, `cmake` and `luarocks` installed, as well as a version of `autoconf`
|
||||
`cmake` and `luarocks` installed, as well as a version of `autoconf`
|
||||
greater than 2.64. You also need `nasm` and of course a compiler like `gcc`
|
||||
or `clang`. If you want to cross-compile for other architectures, you need a proper
|
||||
cross-compile toolchain. Your GCC should be at least of version 4.7 for both native
|
||||
@@ -75,9 +75,11 @@ and cross compiling.
|
||||
|
||||
Users of Debian and Ubuntu can install the required packages using:
|
||||
```
|
||||
sudo apt-get install build-essential libtool gcc-multilib libffi-dev linux-libc-dev:i386 \
|
||||
patch wget unzip git autoconf subversion cmake nasm libsdl1.2-dev luarocks
|
||||
sudo apt-get install build-essential git patch wget unzip \
|
||||
autoconf cmake libtool nasm luarocks \
|
||||
libssl-dev libffi-dev libsdl2-dev linux-libc-dev:i386
|
||||
```
|
||||
Note that the `linux-libc-dev:i386` package is only necessary for x86_64 machines.
|
||||
|
||||
Cross compile toolchains are available for Ubuntu users through these commands:
|
||||
```
|
||||
@@ -95,9 +97,15 @@ Koreader for Android devices.
|
||||
sudo apt-get install ant
|
||||
```
|
||||
|
||||
In order to build Koreader package for Ubuntu Touch, the `click` package management
|
||||
tool is needed, Ubuntu users can install it with:
|
||||
```
|
||||
sudo apt-get install click
|
||||
```
|
||||
|
||||
You might also need SDL library packages if you want to compile and run
|
||||
koreader on Linux PC. Fedora users can install `SDL` and `SDL-devel` package.
|
||||
Ubuntu users probably need to install `libsdl1.2-dev` package:
|
||||
Koreader on Linux PC. Fedora users can install `SDL` and `SDL-devel` package.
|
||||
Ubuntu users probably need to install `libsdl2-dev` package:
|
||||
|
||||
Getting the source
|
||||
========
|
||||
@@ -134,7 +142,7 @@ then similarly with Kindle and Kobo building run this command:
|
||||
make TARGET=pocketbook clean update
|
||||
```
|
||||
|
||||
To build installable package for Ubuntu touch
|
||||
To build installable package for Ubuntu Touch
|
||||
```
|
||||
make TARGET=ubuntu-touch clean update
|
||||
```
|
||||
@@ -176,7 +184,7 @@ If you want to compile the emulator for Windows you need to run:
|
||||
make TARGET=win32 clean && make TARGET=win32
|
||||
```
|
||||
|
||||
To run koreader on your developing machine
|
||||
To run Koreader on your developing machine
|
||||
(you may need to change $(MACHINE) to the arch of your machine such as 'x86_64'):
|
||||
```
|
||||
cd koreader-emulator-$(MACHINE)/koreader && ./reader.lua -d ../../test
|
||||
@@ -276,3 +284,5 @@ http://ccache.samba.org
|
||||
[coverage-badge]:https://coveralls.io/repos/koreader/koreader/badge.svg
|
||||
[coverage-link]:https://coveralls.io/r/koreader/koreader
|
||||
[licence-badge]:http://img.shields.io/badge/licence-AGPL-brightgreen.svg
|
||||
[gitter-badge]:https://badges.gitter.im/Join%20Chat.svg
|
||||
[gitter-link]:https://gitter.im/koreader/koreader?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
||||
|
||||
2
base
2
base
Submodule base updated: d0bed73cd6...05b04b0a20
@@ -1,6 +1,7 @@
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local DocumentRegistry = require("document/documentregistry")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local InputDialog = require("ui/widget/inputdialog")
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local DocSettings = require("docsettings")
|
||||
@@ -321,7 +322,13 @@ function ReaderUI:showReader(file)
|
||||
text = T( _("Opening file '%1'."), file),
|
||||
timeout = 0.1,
|
||||
})
|
||||
UIManager:scheduleIn(0.1, function() self:doShowReader(file) end)
|
||||
UIManager:scheduleIn(0.1, function()
|
||||
DEBUG("creating coroutine for showing reader")
|
||||
local co = coroutine.create(function()
|
||||
self:doShowReader(file)
|
||||
end)
|
||||
coroutine.resume(co)
|
||||
end)
|
||||
end
|
||||
|
||||
local running_instance = nil
|
||||
@@ -338,6 +345,17 @@ function ReaderUI:doShowReader(file)
|
||||
})
|
||||
return
|
||||
end
|
||||
if document.is_locked then
|
||||
DEBUG("document is locked")
|
||||
self._coroutine = coroutine.running() or self._coroutine
|
||||
self:unlockDocumentWithPassword(document)
|
||||
if coroutine.running() then
|
||||
local unlock_success = coroutine.yield()
|
||||
if not unlock_success then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
G_reader_settings:saveSetting("lastfile", file)
|
||||
local reader = ReaderUI:new{
|
||||
@@ -348,6 +366,54 @@ function ReaderUI:doShowReader(file)
|
||||
running_instance = reader
|
||||
end
|
||||
|
||||
function ReaderUI:unlockDocumentWithPassword(document, try_again)
|
||||
DEBUG("show input password dialog")
|
||||
self.password_dialog = InputDialog:new{
|
||||
title = try_again and _("Password is incorrect, try again?")
|
||||
or _("Input document password"),
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Cancel"),
|
||||
enabled = true,
|
||||
callback = function()
|
||||
self:closeDialog()
|
||||
coroutine.resume(self._coroutine)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("OK"),
|
||||
enabled = true,
|
||||
callback = function()
|
||||
local success = self:onVerifyPassword(document)
|
||||
self:closeDialog()
|
||||
if success then
|
||||
coroutine.resume(self._coroutine, success)
|
||||
else
|
||||
self:unlockDocumentWithPassword(document, true)
|
||||
end
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
text_type = "password",
|
||||
width = Screen:getWidth() * 0.8,
|
||||
height = Screen:getHeight() * 0.2,
|
||||
}
|
||||
self.password_dialog:onShowKeyboard()
|
||||
UIManager:show(self.password_dialog)
|
||||
end
|
||||
|
||||
function ReaderUI:onVerifyPassword(document)
|
||||
local password = self.password_dialog:getInputText()
|
||||
return document:unlock(password)
|
||||
end
|
||||
|
||||
function ReaderUI:closeDialog()
|
||||
self.password_dialog:onClose()
|
||||
UIManager:close(self.password_dialog)
|
||||
end
|
||||
|
||||
function ReaderUI:onSetDimensions(dimen)
|
||||
self.dimen = dimen
|
||||
end
|
||||
|
||||
@@ -206,6 +206,7 @@ function KoptInterface:getCachedContext(doc, pageno)
|
||||
-- If kctx is not cached, create one and get reflowed bmp in foreground.
|
||||
local kc = self:createContext(doc, pageno, bbox)
|
||||
local page = doc._document:openPage(pageno)
|
||||
DEBUG("reflowing page", pageno, "in foreground")
|
||||
-- reflow page
|
||||
--local secs, usecs = util.gettime()
|
||||
page:reflow(kc, 0)
|
||||
|
||||
@@ -32,17 +32,17 @@ function PdfDocument:init()
|
||||
self:_readMetadata()
|
||||
end
|
||||
if not (self.info.number_of_pages > 0) then
|
||||
error("No page found in PDF file")
|
||||
--error("No page found in PDF file")
|
||||
end
|
||||
end
|
||||
|
||||
function PdfDocument:unlock(password)
|
||||
if not self._document:authenticatePassword(password) then
|
||||
self._document:close()
|
||||
return false, "wrong password"
|
||||
return false
|
||||
end
|
||||
self.is_locked = false
|
||||
return self:_readMetadata()
|
||||
self:_readMetadata()
|
||||
return true
|
||||
end
|
||||
|
||||
function PdfDocument:getPageTextBoxes(pageno)
|
||||
|
||||
@@ -60,6 +60,7 @@ function InputDialog:init()
|
||||
face = self.input_face,
|
||||
width = self.width * 0.9,
|
||||
input_type = self.input_type,
|
||||
text_type = self.text_type,
|
||||
enter_callback = self.enter_callback,
|
||||
scroll = false,
|
||||
parent = self,
|
||||
|
||||
15
platform/ubuntu-touch/koreader.apparmor.openstore
Normal file
15
platform/ubuntu-touch/koreader.apparmor.openstore
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"policy_groups": [
|
||||
"networking"
|
||||
],
|
||||
"read_path": [
|
||||
"@{HOME}/",
|
||||
"/media/*/*/[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt][Ss]/",
|
||||
"@{PROC}/*/mounts",
|
||||
"/dev/disk/by-label/"
|
||||
],
|
||||
"write_path": [
|
||||
"@{HOME}/"
|
||||
],
|
||||
"policy_version": 1.2
|
||||
}
|
||||
@@ -21,3 +21,30 @@ Input.dummy = true
|
||||
-- turn on debug
|
||||
local DEBUG = require("dbg")
|
||||
--DEBUG:turnOn()
|
||||
|
||||
function assertAlmostEquals(expected, actual, margin)
|
||||
if type(actual) ~= 'number' or type(expected) ~= 'number'
|
||||
or type(margin) ~= 'number' then
|
||||
error('assertAlmostEquals: must supply only number arguments.', 2)
|
||||
end
|
||||
|
||||
assert(math.abs(expected - actual) <= margin,
|
||||
'Values are not almost equal\n'
|
||||
.. 'Expected: ' .. expected .. ' with margin of ' .. margin
|
||||
.. ', received: ' .. actual
|
||||
)
|
||||
end
|
||||
|
||||
function assertNotAlmostEquals(expected, actual, margin)
|
||||
if type(actual) ~= 'number' or type(expected) ~= 'number'
|
||||
or type(margin) ~= 'number' then
|
||||
error('assertAlmostEquals: must supply only number arguments.', 2)
|
||||
end
|
||||
|
||||
assert(math.abs(expected - actual) > margin,
|
||||
'Values are almost equal\n'
|
||||
.. 'Expected: ' .. expected .. ' with margin of ' .. margin
|
||||
.. ', received: ' .. actual
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -13,6 +13,12 @@ describe("PDF document module", function()
|
||||
assert.are.same(dimen.w, 567)
|
||||
assert.are.same(dimen.h, 1418)
|
||||
end)
|
||||
it("should get cover image", function()
|
||||
local image = doc:getCoverPageImage()
|
||||
assert.truthy(image)
|
||||
assert.are.same(320, image:getWidth())
|
||||
assert.are.same(800, image:getHeight())
|
||||
end)
|
||||
local pos0 = {page = 1, x = 0, y = 20}
|
||||
local pos1 = {page = 1, x = 300, y = 120}
|
||||
local pboxes = {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
require("commonrequire")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local HTTPClient = require("httpclient")
|
||||
local DEBUG = require("dbg")
|
||||
--DEBUG:turnOn()
|
||||
|
||||
@@ -15,8 +14,9 @@ describe("HTTP client module #notest #nocov", function()
|
||||
assert(not res.error, "error occurs")
|
||||
assert(res.body)
|
||||
end
|
||||
local async_client = HTTPClient:new()
|
||||
it("should get response from async GET request", function()
|
||||
local HTTPClient = require("httpclient")
|
||||
local async_client = HTTPClient:new()
|
||||
UIManager:quit()
|
||||
local urls = {
|
||||
"http://www.example.com",
|
||||
|
||||
83
spec/unit/koptinterface_spec.lua
Normal file
83
spec/unit/koptinterface_spec.lua
Normal file
@@ -0,0 +1,83 @@
|
||||
require("commonrequire")
|
||||
local DocumentRegistry = require("document/documentregistry")
|
||||
local Koptinterface = require("document/koptinterface")
|
||||
local Cache = require("cache")
|
||||
local DEBUG = require("dbg")
|
||||
DEBUG:turnOn()
|
||||
|
||||
describe("Koptinterface module", function()
|
||||
local sample_pdf = "spec/front/unit/data/tall.pdf"
|
||||
local doc
|
||||
|
||||
before_each(function()
|
||||
doc = DocumentRegistry:openDocument(sample_pdf)
|
||||
Cache:clear()
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
doc:close()
|
||||
end)
|
||||
|
||||
it("should get auto bbox", function()
|
||||
local auto_bbox = Koptinterface:getAutoBBox(doc, 1)
|
||||
assertAlmostEquals(22, auto_bbox.x0, 0.5)
|
||||
assertAlmostEquals(38, auto_bbox.y0, 0.5)
|
||||
assertAlmostEquals(548, auto_bbox.x1, 0.5)
|
||||
assertAlmostEquals(1387, auto_bbox.y1, 0.5)
|
||||
end)
|
||||
|
||||
it("should get semi auto bbox", function()
|
||||
local semiauto_bbox = Koptinterface:getSemiAutoBBox(doc, 1)
|
||||
local page_bbox = doc:getPageBBox(1)
|
||||
doc.bbox[1] = {
|
||||
x0 = page_bbox.x0 + 10,
|
||||
y0 = page_bbox.y0 + 10,
|
||||
x1 = page_bbox.x1 - 10,
|
||||
y1 = page_bbox.y1 - 10,
|
||||
}
|
||||
|
||||
local bbox = Koptinterface:getSemiAutoBBox(doc, 1)
|
||||
assertNotAlmostEquals(semiauto_bbox.x0, bbox.x0, 0.5)
|
||||
assertNotAlmostEquals(semiauto_bbox.y0, bbox.y0, 0.5)
|
||||
assertNotAlmostEquals(semiauto_bbox.x1, bbox.x1, 0.5)
|
||||
assertNotAlmostEquals(semiauto_bbox.y1, bbox.y1, 0.5)
|
||||
end)
|
||||
|
||||
it("should render optimized page to de-watermark", function()
|
||||
local page_dimen = doc:getPageDimensions(1, 1.0, 0)
|
||||
local tile = Koptinterface:renderOptimizedPage(doc, 1, nil,
|
||||
1.0, 0, 0)
|
||||
assert.truthy(tile)
|
||||
assert.are.same(page_dimen, tile.excerpt)
|
||||
end)
|
||||
|
||||
it("should reflow page in foreground", function()
|
||||
doc.configurable.text_wrap = 1
|
||||
local kc = Koptinterface:getCachedContext(doc, 1)
|
||||
assert.truthy(kc)
|
||||
end)
|
||||
|
||||
it("should hint reflowed page in background", function()
|
||||
doc.configurable.text_wrap = 1
|
||||
Koptinterface:hintReflowedPage(doc, 1, 1.0, 0, 1.0, 0)
|
||||
-- and wait for reflowing to complete
|
||||
local kc = Koptinterface:getCachedContext(doc, 1)
|
||||
assert.truthy(kc)
|
||||
end)
|
||||
|
||||
it("should get native text boxes", function()
|
||||
local kc = Koptinterface:getCachedContext(doc, 1)
|
||||
local boxes = Koptinterface:getNativeTextBoxes(doc, 1)
|
||||
local lines_in_native_page = #boxes
|
||||
assert.truthy(lines_in_native_page == 60)
|
||||
end)
|
||||
|
||||
it("should get reflow text boxes", function()
|
||||
doc.configurable.text_wrap = 1
|
||||
local kc = Koptinterface:getCachedContext(doc, 1)
|
||||
local boxes = Koptinterface:getReflowedTextBoxes(doc, 1)
|
||||
local lines_in_reflowed_page = #boxes
|
||||
assert.truthy(lines_in_reflowed_page > 60)
|
||||
end)
|
||||
|
||||
end)
|
||||
@@ -1,6 +1,5 @@
|
||||
require("commonrequire")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local HTTPClient = require("httpclient")
|
||||
local DEBUG = require("dbg")
|
||||
local md5 = require("MD5")
|
||||
--DEBUG:turnOn()
|
||||
@@ -58,6 +57,7 @@ local service = [[
|
||||
]]
|
||||
|
||||
describe("KOSync modules #notest #nocov", function()
|
||||
local HTTPClient = require("httpclient")
|
||||
local Spore = require("Spore")
|
||||
local client = Spore.new_from_string(service)
|
||||
package.loaded['Spore.Middleware.GinClient'] = {}
|
||||
|
||||
22
spec/unit/verbose_print.lua
Normal file
22
spec/unit/verbose_print.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
-- from Mashape/kong/spec/busted-print.lua
|
||||
local ansicolors = require 'ansicolors'
|
||||
|
||||
return function(options)
|
||||
local handler = require 'busted.outputHandlers.utfTerminal'(options)
|
||||
|
||||
handler.fileStart = function(file)
|
||||
io.write('\n' .. ansicolors('%{cyan}' .. file.name) .. ':')
|
||||
end
|
||||
|
||||
handler.testStart = function(element, parent, status, debug)
|
||||
io.write('\n ' .. handler.getFullName(element) .. ' ... ')
|
||||
io.flush()
|
||||
end
|
||||
|
||||
local busted = require 'busted'
|
||||
|
||||
busted.subscribe({ 'file', 'start' }, handler.fileStart)
|
||||
busted.subscribe({ 'test', 'start' }, handler.testStart)
|
||||
|
||||
return handler
|
||||
end
|
||||
Reference in New Issue
Block a user