mirror of
https://github.com/kiwix/libkiwix.git
synced 2025-12-24 15:07:59 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ea701b6d6 |
12
.codecov.yml
12
.codecov.yml
@@ -1,12 +0,0 @@
|
||||
codecov:
|
||||
notify:
|
||||
require_ci_to_pass: yes
|
||||
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
threshold: 1%
|
||||
|
||||
ignore:
|
||||
- "test"
|
||||
12
.github/FUNDING.yml
vendored
12
.github/FUNDING.yml
vendored
@@ -1,12 +0,0 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: kiwix
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # https://kiwix.org/support-us/
|
||||
15
.github/stale.yml
vendored
15
.github/stale.yml
vendored
@@ -1,15 +0,0 @@
|
||||
daysUntilClose: false
|
||||
staleLabel: stale
|
||||
|
||||
issues:
|
||||
daysUntilStale: 60
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be now be reviewed manually. Thank you
|
||||
for your contributions.
|
||||
pulls:
|
||||
daysUntilStale: 7
|
||||
markComment: >
|
||||
This pull request has been automatically marked as stale because it has not had
|
||||
recent activity. It will be now be reviewed manually. Thank you
|
||||
for your contributions.
|
||||
200
.github/workflows/ci.yml
vendored
200
.github/workflows/ci.yml
vendored
@@ -1,200 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
macOS:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target:
|
||||
- macos-aarch64-dyn
|
||||
- macos-x86_64-dyn
|
||||
- ios-arm64-dyn
|
||||
- ios-x86_64-dyn
|
||||
include:
|
||||
- target: macos-aarch64-dyn
|
||||
arch_name: arm64-apple-macos
|
||||
run_test: true
|
||||
- target: macos-x86_64-dyn
|
||||
arch_name: x86_64-apple-darwin
|
||||
run_test: true
|
||||
- target: ios-arm64-dyn
|
||||
arch_name: aarch64-apple-ios
|
||||
run_test: false
|
||||
- target: ios-x86_64-dyn
|
||||
arch_name: x86-apple-ios-simulator
|
||||
run_test: false
|
||||
runs-on: macos-15
|
||||
|
||||
env:
|
||||
HOME: /Users/runner
|
||||
steps:
|
||||
- name: Retrieve source code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install packages
|
||||
run: |
|
||||
brew update
|
||||
brew install ninja meson
|
||||
|
||||
- name: Install dependencies
|
||||
uses: kiwix/kiwix-build/actions/dl_deps_archive@main
|
||||
with:
|
||||
target_platform: ${{ matrix.target }}
|
||||
|
||||
- name: Compile
|
||||
env:
|
||||
PKG_CONFIG_PATH: ${{env.HOME}}/BUILD_${{matrix.arch_name}}/INSTALL/lib/pkgconfig
|
||||
CPPFLAGS: -I${{env.HOME}}/BUILD_${{matrix.arch_name}}/INSTALL/include
|
||||
MESON_OPTION: --default-library=shared -Db_coverage=true
|
||||
MESON_CROSSFILE: ${{env.HOME}}/BUILD_${{matrix.arch_name}}/meson_cross_file.txt
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -e $MESON_CROSSFILE ]; then
|
||||
MESON_OPTION="$MESON_OPTION --cross-file $MESON_CROSSFILE -Dstatic-linkage=true"
|
||||
fi
|
||||
meson . build ${MESON_OPTION}
|
||||
ninja -C build
|
||||
|
||||
- name: Test libkiwix
|
||||
if: matrix.run_test
|
||||
env:
|
||||
SKIP_BIG_MEMORY_TEST: 1
|
||||
LD_LIBRARY_PATH: ${{env.HOME}}/BUILD_${{matrix.arch_name}}/INSTALL/lib:${{env.HOME}}/BUILD_${{matrix.arch_name}}/INSTALL/lib64
|
||||
run: meson test -C build --verbose
|
||||
|
||||
Windows:
|
||||
runs-on: windows-2022
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install packages
|
||||
run:
|
||||
choco install pkgconfiglite ninja
|
||||
|
||||
- name: Install python modules
|
||||
run: pip3 install meson
|
||||
|
||||
- name: Setup MSVC compiler
|
||||
uses: bus1/cabuild/action/msdevshell@v1
|
||||
with:
|
||||
architecture: x64
|
||||
|
||||
- name: Install dependencies
|
||||
uses: kiwix/kiwix-build/actions/dl_deps_archive@main
|
||||
with:
|
||||
target_platform: win-x86_64-static
|
||||
|
||||
- name: Compile
|
||||
shell: cmd
|
||||
run: |
|
||||
set PKG_CONFIG_PATH=%cd%\BUILD_win-amd64\INSTALL\lib\pkgconfig
|
||||
set CPPFLAGS=-I%cd%\BUILD_win-amd64\INSTALL\include
|
||||
meson.exe setup . build -Dwerror=false --default-library=static --buildtype=release
|
||||
cd build
|
||||
ninja.exe
|
||||
|
||||
- name: Test
|
||||
shell: cmd
|
||||
run: |
|
||||
cd build
|
||||
meson.exe test --verbose
|
||||
env:
|
||||
WAIT_TIME_FACTOR_TEST: 10
|
||||
|
||||
Linux:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target:
|
||||
- linux-x86_64-static
|
||||
- linux-x86_64-dyn
|
||||
- android-arm
|
||||
- android-arm64
|
||||
image_variant: ['jammy']
|
||||
include:
|
||||
- target: linux-x86_64-static
|
||||
lib_postfix: '/x86_64-linux-gnu'
|
||||
arch_name: linux-x86_64
|
||||
run_test: true
|
||||
coverage: true
|
||||
- target: linux-x86_64-dyn
|
||||
lib_postfix: '/x86_64-linux-gnu'
|
||||
arch_name: linux-x86_64
|
||||
run_test: true
|
||||
coverage: true
|
||||
- target: android-arm
|
||||
lib_postfix: '/arm-linux-androideabi'
|
||||
arch_name: arm-linux-androideabi
|
||||
run_test: false
|
||||
coverage: false
|
||||
- target: android-arm64
|
||||
lib_postfix: '/aarch64-linux-android'
|
||||
arch_name: aarch64-linux-android
|
||||
run_test: false
|
||||
coverage: false
|
||||
env:
|
||||
HOME: /home/runner
|
||||
runs-on: ubuntu-22.04
|
||||
container:
|
||||
image: "ghcr.io/kiwix/kiwix-build_ci_${{matrix.image_variant}}:2025-06-07"
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
uses: kiwix/kiwix-build/actions/dl_deps_archive@main
|
||||
with:
|
||||
target_platform: ${{ matrix.target }}
|
||||
- name: Compile
|
||||
shell: bash
|
||||
run: |
|
||||
meson --version
|
||||
if [[ "${{matrix.target}}" =~ .*-dyn ]]; then
|
||||
MESON_OPTION="--default-library=shared"
|
||||
else
|
||||
MESON_OPTION="--default-library=static"
|
||||
fi
|
||||
if [ -e "${{env.HOME}}/BUILD_${{matrix.arch_name}}/meson_cross_file.txt" ]; then
|
||||
MESON_OPTION="$MESON_OPTION --cross-file ${{env.HOME}}/BUILD_${{matrix.arch_name}}/meson_cross_file.txt"
|
||||
else
|
||||
MESON_OPTION="$MESON_OPTION -Db_coverage=true"
|
||||
fi
|
||||
if [[ "${{matrix.target}}" =~ android-.* ]]; then
|
||||
MESON_OPTION="$MESON_OPTION -Dstatic-linkage=true"
|
||||
fi
|
||||
meson . build ${MESON_OPTION}
|
||||
cd build
|
||||
ninja
|
||||
env:
|
||||
PKG_CONFIG_PATH: "/home/runner/BUILD_${{matrix.arch_name}}/INSTALL/lib/pkgconfig:/home/runner/BUILD_${{matrix.arch_name}}/INSTALL/lib${{matrix.lib_postfix}}/pkgconfig"
|
||||
CPPFLAGS: "-I/home/runner/BUILD_${{matrix.arch_name}}/INSTALL/include"
|
||||
- name: Test
|
||||
if: matrix.run_test
|
||||
shell: bash
|
||||
run: |
|
||||
cd build
|
||||
meson test --verbose
|
||||
if [[ "${{matrix.coverage}}" = "true" ]]; then
|
||||
ninja coverage
|
||||
fi
|
||||
env:
|
||||
LD_LIBRARY_PATH: "/home/runner/BUILD_${{matrix.arch_name}}/INSTALL/lib:/home/runner/BUILD_${{matrix.arch_name}}/INSTALL/lib${{matrix.lib_postfix}}"
|
||||
SKIP_BIG_MEMORY_TEST: 1
|
||||
|
||||
- name: Publish coverage
|
||||
if: matrix.coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
111
.github/workflows/package.yml
vendored
111
.github/workflows/package.yml
vendored
@@ -1,111 +0,0 @@
|
||||
name: Packages
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build-deb:
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
distro:
|
||||
# - debian-unstable
|
||||
# - debian-trixie
|
||||
# - debian-bookworm
|
||||
# - debian-bullseye
|
||||
- ubuntu-noble
|
||||
- ubuntu-jammy
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Determine which PPA we should upload to
|
||||
- name: PPA
|
||||
id: ppa
|
||||
run: |
|
||||
if [[ $REF == refs/tags* ]]
|
||||
then
|
||||
echo "ppa=kiwixteam/release" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "ppa=kiwixteam/dev" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
env:
|
||||
REF: ${{ github.ref }}
|
||||
|
||||
- uses: legoktm/gh-action-auto-dch@main
|
||||
with:
|
||||
fullname: Kiwix builder
|
||||
email: release+launchpad@kiwix.org
|
||||
distro: ${{ matrix.distro }}
|
||||
|
||||
# - uses: legoktm/gh-action-build-deb@debian-unstable
|
||||
# if: matrix.distro == 'debian-unstable'
|
||||
# name: Build package for debian-unstable
|
||||
# id: build-debian-unstable
|
||||
# with:
|
||||
# args: --no-sign
|
||||
#
|
||||
# - uses: legoktm/gh-action-build-deb@b47978ba8498dc8b8153cc3b5f99a5fc1afa5de1 # pin@debian-trixie
|
||||
# if: matrix.distro == 'debian-trixie'
|
||||
# name: Build package for debian-trixie
|
||||
# id: build-debian-trixie
|
||||
# with:
|
||||
# args: --no-sign
|
||||
#
|
||||
# - uses: legoktm/gh-action-build-deb@1f4e86a6bb34aaad388167eaf5eb85d553935336 # pin@debian-bookworm
|
||||
# if: matrix.distro == 'debian-bookworm'
|
||||
# name: Build package for debian-bookworm
|
||||
# id: build-debian-bookworm
|
||||
# with:
|
||||
# args: --no-sign
|
||||
#
|
||||
# - uses: legoktm/gh-action-build-deb@084b4263209252ec80a75d2c78a586192c17f18d # pin@debian-bullseye
|
||||
# if: matrix.distro == 'debian-bullseye'
|
||||
# name: Build package for debian-bullseye
|
||||
# id: build-debian-bullseye
|
||||
# with:
|
||||
# args: --no-sign
|
||||
|
||||
- uses: legoktm/gh-action-build-deb@9114a536498b65c40b932209b9833aa942bf108d # pin@ubuntu-noble
|
||||
if: matrix.distro == 'ubuntu-noble'
|
||||
name: Build package for ubuntu-noble
|
||||
id: build-ubuntu-noble
|
||||
with:
|
||||
args: --no-sign
|
||||
ppa: ${{ steps.ppa.outputs.ppa }}
|
||||
|
||||
- uses: legoktm/gh-action-build-deb@ubuntu-jammy
|
||||
if: matrix.distro == 'ubuntu-jammy'
|
||||
name: Build package for ubuntu-jammy
|
||||
id: build-ubuntu-jammy
|
||||
with:
|
||||
args: --no-sign
|
||||
ppa: ${{ steps.ppa.outputs.ppa }}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Packages for ${{ matrix.distro }}
|
||||
path: output
|
||||
|
||||
- uses: legoktm/gh-action-dput@main
|
||||
name: Upload dev package
|
||||
# Only upload on pushes to main
|
||||
if: github.event_name == 'push' && github.event.ref == 'refs/heads/main' && startswith(matrix.distro, 'ubuntu-')
|
||||
with:
|
||||
gpg_key: ${{ secrets.LAUNCHPAD_GPG }}
|
||||
repository: ppa:kiwixteam/dev
|
||||
packages: output/*_source.changes
|
||||
|
||||
- uses: legoktm/gh-action-dput@main
|
||||
name: Upload release package
|
||||
if: github.event_name == 'release' && startswith(matrix.distro, 'ubuntu-')
|
||||
with:
|
||||
gpg_key: ${{ secrets.LAUNCHPAD_GPG }}
|
||||
repository: ppa:kiwixteam/release
|
||||
packages: output/*_source.changes
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,9 +0,0 @@
|
||||
.idea/
|
||||
*.swp
|
||||
subprojects/googletest-release*
|
||||
*.class
|
||||
build/
|
||||
.vscode/
|
||||
builddir/
|
||||
.cache/
|
||||
.clangd/
|
||||
@@ -1,21 +0,0 @@
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Set the version of Python and other tools you might need
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.11"
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
||||
# We recommend specifying your dependencies to enable reproducible builds:
|
||||
# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
|
||||
python:
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
36
.travis.yml
Normal file
36
.travis.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
language: cpp
|
||||
dist: trusty
|
||||
sudo: false
|
||||
cache: ccache
|
||||
before_install:
|
||||
- PATH=$PATH:$HOME/bin
|
||||
install: travis/install_deps.sh
|
||||
script: travis/compile.sh
|
||||
env:
|
||||
matrix:
|
||||
- PLATFORM="native_static"
|
||||
- PLATFORM="native_dyn"
|
||||
- PLATFORM="win32_static"
|
||||
- PLATFORM="win32_dyn"
|
||||
- PLATFORM="android_arm"
|
||||
- PLATFORM="android_arm64"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- cmake
|
||||
- python3-pip
|
||||
- libbz2-dev
|
||||
- ccache
|
||||
- zlib1g-dev
|
||||
- uuid-dev
|
||||
- libctpp2-dev
|
||||
- ctpp2-utils
|
||||
- libmicrohttpd-dev
|
||||
- g++-mingw-w64-i686
|
||||
- gcc-mingw-w64-i686
|
||||
- gcc-mingw-w64-base
|
||||
- mingw-w64-tools
|
||||
matrix:
|
||||
include:
|
||||
- env: PLATFORM="native_dyn"
|
||||
os: osx
|
||||
4
COPYING
4
COPYING
@@ -77,7 +77,7 @@ modification follow.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
@@ -510,7 +510,7 @@ actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
|
||||
553
ChangeLog
553
ChangeLog
@@ -1,555 +1,3 @@
|
||||
libkiwix 14.1.1
|
||||
===============
|
||||
|
||||
* Server:
|
||||
- Fix regression for kiwix-serve --nosearchbar (@veloman-yunkan #1250)
|
||||
- Avoid results content interpretation... crash in fulltext search (@vighnesh-sawant #1241)
|
||||
- Fix for intermittent /content/blank.html errors (@veloman-yunkan #1249)
|
||||
|
||||
libkiwix 14.1.0
|
||||
===============
|
||||
|
||||
* Server:
|
||||
- Viewer detects & tracks intrapage navigation anchors too (@veloman-yunkan #1213)
|
||||
- Add support for catalog only mode (@veloman-yunkan #1219)
|
||||
- Add API which returns server access url (@vighnesh-sawant #1234)
|
||||
- Fix chrome searchbar placeholder text overflow (@aditii2712 #1185)
|
||||
- Fix magnet link queryStyring (@rgaudin #1160)
|
||||
- Improve chrome printing stylesheet (@kelson42 #1202)
|
||||
- Default white background (@kelson42 #1205)
|
||||
|
||||
* Other:
|
||||
- Switched to the new libzim illustrations API (@veloman-yunkan #1226)
|
||||
- Stop building Windows with DEBUG symbols in CI (@kelson42 #1165)
|
||||
- Update many things in the CI/CD (@kelson42 #1203 #1194 #1209 #1207 #1235)
|
||||
- Requires now libzim 9.4.0 (@kelson42 #1231)
|
||||
- Fix compilation for FreeBSD (@OICe2 #1173 #1174)
|
||||
- Wait up to 1s to let aria2c to start before complaining (@kelson42 #1169)
|
||||
|
||||
libkiwix 14.0.0
|
||||
===============
|
||||
|
||||
* Server:
|
||||
- Support of IPv6 (@veloman-yunkan @aryanA101a #1074 #1093)
|
||||
- Better public IP configuration/detection (@sgourdas #1132)
|
||||
- Fix API errors in catalog searches if Xapian keyword in used (@veloman-yunkan #1137)
|
||||
- Clearly define which Web browsers are supported (@kelson42 @rgaudin @jaifroid @benoit74 #1132)
|
||||
- Improve welcome page download buttons (@veloman-yunkan #1094)
|
||||
- Better handling of external (non-HTTP) links (@veloman-yunkan #1123)
|
||||
- Fix book illustration size on welcome page to 48x48 pixels (@veloman-yunkan #1127)
|
||||
- Remove "Multiple Languages" in language filter (@veloman-yunkan #1098)
|
||||
- Stop transforming tags casing (@kelson42 @veloman-yunkan #1079 #1121)
|
||||
- ZIM file size consistently advertised in MiB (@harsha-mangena #1132)
|
||||
- Few new supported languages in the filter (@kelson42 #1080)
|
||||
- Improve accesskeys (@kelson42 #1075)
|
||||
- Add OpenSearch <link> to head of pages (@kelson42 #1070)
|
||||
* Compilation/Packaging:
|
||||
- Multiple fixes around deb packaging (@kelson42 #1108 #1114 #1135)
|
||||
- Generating of libkiwix.pc via Meson (@veloman-yunkan #1133)
|
||||
- Native Windows CI/CD (@mgautierfr @kelson42 #1113 #1125)
|
||||
- Better check (maximum) libzim version (@kelson42 #1124)
|
||||
- Multiple automated tests improvements (@veloman-yunkan #1068 #1067)
|
||||
* Other:
|
||||
- Deleted supported env. variable `$KIWIX_DATA_DIR` and `kiwix::getDataDirectory()` (@sgourdas #1107)
|
||||
- New string slugification for filenames (@shaopenglin #1105)
|
||||
- Multiple improvements around aria2c download mgmt. (@veloman-yunkan #1097)
|
||||
|
||||
libkiwix 13.1.0
|
||||
===============
|
||||
|
||||
* Server:
|
||||
- Properly translated error pages (@veloman-yunkan #1032)
|
||||
- Properly translated search result page (@veloman-yunkan #1046)
|
||||
- Default UI language is resolved in frontend (@veloman-yunkan #1044)
|
||||
- Better support of older Web browsers by polyfilling replaceAll() (@veloman-yunkan #1054)
|
||||
* New API to migrate bookmarks between books (@mgautierfr #1043)
|
||||
* Fixed compilation on Haiku OS (@Begasus #1048)
|
||||
|
||||
libkiwix 13.0.0
|
||||
===============
|
||||
|
||||
* Server:
|
||||
- Improved look & feel of kiwix-serve UI (@veloman-yunkan #917 #1021)
|
||||
- Increase tolerance to malformed (control characters) ZIM entry titles (@veloman-yunkan #1023)
|
||||
- API allowing to filter many categories at once (@juuz0 #974)
|
||||
- Cookie-less user language control (@veloman-yumkan #997)
|
||||
- Hack to fix Mirrorbrain based broken magnet URLs (@rgaudin #1001)
|
||||
* Fix handling of books with 'Name' metadata with dots (@mgautier #1016)
|
||||
* New method beautifyFileSize() to provide nice-looking book sizes (@vuuz0 #971)
|
||||
* Fix a few missing includes (@mgautierfr #978)
|
||||
* New functions to read - kiwix-serve - languages and categories streams (@juuz0 #967)
|
||||
* Add support of Fon language (@kelson42 #1013)
|
||||
* C++17 code base compliancy (@mgautierfr #996)
|
||||
* Use everywhere std::shared_ptr in place of raw pointer (@mgautierfr #991)
|
||||
* Do not use [[nodiscard]] attribute on compiler not supporting it (@mgautierfr #1003)
|
||||
* Add a non minified version of autoComplete.js (@mgautierfr #1008)
|
||||
* Multiple CI/CD improvements (@kelson42 #982)
|
||||
|
||||
libkiwix 12.1.0
|
||||
===============
|
||||
|
||||
* Server:
|
||||
- Introduce a `/nojs` endpoint to browse catalog and zim files with a browser without js (@juuz0 #897)
|
||||
- Translate the viewer (@veloman-yunkan #871 #846)
|
||||
- Display `mul` on tile when zim is multi-languages (@juuz0 #934)
|
||||
- Suggestion links point to the `/content` endpoint (@veloman-yunkan #862)
|
||||
- Correctly compress web fonts in http answers (@kelson42 #856)
|
||||
- Correctly encode link in suggestions (@veloman-yunkan #859 #860 #963)
|
||||
- Correctly encode url redirection (@veloman-yunkan #866 #890)
|
||||
- Properly handle user language, through cookies and http headers (@veloman-yunkan #849 #869)
|
||||
- Fix url encoding (@veloman-yunkan #870)
|
||||
- Fix viewer for viewer for SeaMonkey (@veloman-yunkan #887)
|
||||
- Make the downloader threadsafe (@mgautierfr #886)
|
||||
- Add RSS feed in the main page (pointing to the catalog) (@juuz0 #882 #920)
|
||||
- Correctly set the mimetype for json and ico (@veloman-yunkan #892)
|
||||
- `count=-1` correspond to unlimited count (instead of 0) (@veloman-yunkan #894)
|
||||
- Keep the navigation bar on top (@juuz0 #896)
|
||||
- Make the viewer's iframe "safe" (@veloman-yunkan #906 #930)
|
||||
- Correctly escape search link in XML Opds output (@veloman-yunkan #936)
|
||||
- Store values needed for the viewer js in the url fragment instead of the query string (@juuz0 #907)
|
||||
- Get rid of legacy OPDS API usage in the viewer (@veloman-yunkan #939)
|
||||
- Fix charset encoding declaration in OPDS response MIME types (@veloman-yunkan #942)
|
||||
- Fix PDF in the viewer (@veloman-yunkan #940)
|
||||
- Fix external links handling in the viewer (@veloman-yunkan #959)
|
||||
- Add tests of searching with accents (@mgautierfs #954)
|
||||
* Fix handling of missing illustration in the book (@veloman-yunkan #961)
|
||||
* Add support for multi languages zim files (@veloman-yunkan #904)
|
||||
* Fix includes for openbsd (@bentley #949)
|
||||
* Fix pathes in git to allow git clone on Windows (@adamlamar #868)
|
||||
* Switch to `main` as principal branch (instead of `master`) (@kelson42)
|
||||
* Remove libkiwix android publisher from the repository (@kelson42 #884)
|
||||
* Various fixes of meson and CI. (@mgautierfr @kelson42)
|
||||
|
||||
libkiwix 12.0.0
|
||||
===============
|
||||
|
||||
* [API Break] Remove wrapper around libzim (@mgautierfr #789)
|
||||
* Allow kiwix-serve to use custom resource files (@veloman-yunkan #779)
|
||||
* Properly handle searchProtocolPrefix when rendering search result (@veloman-yunkan #823)
|
||||
* Prevent search on multi language content (@veloman-yunkan #838)
|
||||
* Use new `zim::Archive::getMediaCount` from libzim (@mgautierfr #836)
|
||||
* Catalog:
|
||||
- Include tags in free text catalog search (@veloman-yunkan #802)
|
||||
- Illustration's url is based on book's uuid (@veloman-yunkan #804)
|
||||
- Cleanup of the opds-dumper (@veloman-yunkan #829)
|
||||
- Allow filtering of catalog content using multiple languages (@veloman-yunkan #841)
|
||||
- Make opds-dumper respect the namemapper (@mgautierfr #837)
|
||||
* Server:
|
||||
- Correctly handle `\` in suggestion json generation (@veloman-yunkan #843)
|
||||
- Better http caching (@veloman-yunkan #833)
|
||||
- Make `/suggest` endpoint thread-safe (@veloman-yunkan #834)
|
||||
- Better redirection of main page (@veloman-yunkan #827)
|
||||
- Remove jquery (@mgautierfr @juuz0 #796)
|
||||
- Better Viewer of zim content :
|
||||
. Introduce `/content` endpoints (@veloman-yunkan #806)
|
||||
. Switch to iframe based content viewer (@veloman-yunkan #716)
|
||||
- Optimised design of the welcome page:
|
||||
. Alignement (@juuz0 @kelson42 #786)
|
||||
. Exit download modal on pressing escape key (@juzz0 #800)
|
||||
. Add favicon for different devices (@juzz0 #805)
|
||||
. Fix auto hidding of the toolbar (@veloman-yunkan #821)
|
||||
. Allow user to filter books by tags in the front page (@juuz0 #711)
|
||||
* CI :
|
||||
- Trigger CI on pull_request (@kelson42 #791)
|
||||
- Drop Ubuntu Impish packaging (@legoktm #825)
|
||||
- Add Ubuntu Kinetic packaging (@legoktm #801)
|
||||
* Testing:
|
||||
- Test ICULanguageInfo (@veloman-yunkan #795)
|
||||
- Introduce fake `test` language to test i18n (@veloman-yunkan #848)
|
||||
* Fix documentation (@kelson42 #816)
|
||||
* Udpate translation (#787 #839 #847)
|
||||
|
||||
libkiwix 11.0.0
|
||||
===============
|
||||
|
||||
* [server] Add support for internationalization (@veloman-yunkan #679)
|
||||
* [server] Use gzip compression instead of deflat (mgautierfr #757)
|
||||
* [server] Version the static resources. This allow better invalidating
|
||||
browser cache when resources are changed (@veloman-yunkan #712)
|
||||
* [server|front] Use integer to query the host for page length (@juuz0 #772)
|
||||
* [server] Improve multizim search API:
|
||||
- Improvement of the cache system
|
||||
- Better API to select on which books to search in.
|
||||
- SysAdmin is now able to limit the number of book we search in for a multizim search
|
||||
* [server] Introduce a opensearch API for multizim fulltext search
|
||||
* [wrapper] Remove java wrapper
|
||||
* Testing:
|
||||
- Testing of search result pages content (@veloman-yunkan #765)
|
||||
- Better testing structure of xml search result (@veloman-yunkan #780)
|
||||
|
||||
libkiwix 10.1.1
|
||||
===============
|
||||
|
||||
* Correctly detect the number of article for older zims (<=6) (@mgautier #743)
|
||||
* [server] Fix fulltext search (@mgautierfr #724)
|
||||
* [server][internal] New way to build Error message (@veloman-yunkan #732 #738 #744)
|
||||
* Fix CI (@mgautierfr #736)
|
||||
|
||||
libkiwix 10.1.0
|
||||
===============
|
||||
|
||||
This release is an important one as it fixes a Xss vulnerability introduced
|
||||
in libkiwix 10.0.0
|
||||
|
||||
* [SECURITY] Fix a Xss attack vulnerability (introduced in 10.0.0) (@juuz0 #721)
|
||||
* [server] Add a option to set a limit on the number of connexion per IP (@kelson42 #700)
|
||||
* [server] Do not display a lang tag in the UI if the book has no language (@juuz0 #706)
|
||||
* [server] Add the book title associated to a search results (@thavelick #705, @mgautierfr #718)
|
||||
* Add `dc:issued` to opds output stream (@veloman-yunkan #715)
|
||||
* Add handling of several languages not provided by ICU (@juuz0 #701)
|
||||
* [server] Add a caching system for search and suggestion (@maneeshpm #620)
|
||||
* Fix cross-compilation (@kelson42 #703)
|
||||
* Add unit-testing of suggestions and error pages (@veloman-yunkan #709 #710 #727)
|
||||
* Better testing system of html response (@veloman-yunkan #725)
|
||||
|
||||
libkiwix 10.0.1
|
||||
===============
|
||||
|
||||
* [server] The catalog search interpret `count=0` as no limit.
|
||||
This was the case for a long time. This was changed unintentionally
|
||||
(@veloman-yunkan #686)
|
||||
* [server] Correctly generere a human friendly title in the server frontend.
|
||||
(@juuz0 #687, @kelson42 #689)
|
||||
* [server] Fix download button if there is no url do download from.
|
||||
(@juuz0 #691)
|
||||
* Add non-minified isotope.pkdg.js
|
||||
Needed for debian packaging as we need the source and minified version is
|
||||
not the source (@legoktm #693)
|
||||
* [server] Add a tooltip with the full language for the lang tag.
|
||||
* CI fixes (@kelson42 @legoktm)
|
||||
|
||||
libkiwix 10.0.0
|
||||
===============
|
||||
|
||||
This release is huge release.
|
||||
The project has been renamed to libkiwix, it is more coherent with the library name.
|
||||
|
||||
* Server front page :
|
||||
- Use js in the front page to display the available book,
|
||||
using the OPDS stream as source. The front page is now populated only with
|
||||
the visible books and user can search for books. (@MananJethwany #530, #541, #534)
|
||||
(@kelson42 #628)
|
||||
- Revamp css (@MananJethwany #559)
|
||||
- Correctly Convert 3iso language code to 2iso (@juuz0 #672)
|
||||
|
||||
* Server suggestions search :
|
||||
- Add pagination for suggestion search (@maneeshpm #591)
|
||||
- Fix suggestion system (@MananJethwany #498)
|
||||
- Provide the kind and path (when adapted) to the suggestion answer (@MananJethwany #464)
|
||||
- The displayed suggestion have now highligth on the searched terms (@maneeshpm #505)
|
||||
- Properly handle html encoding of suggestions (@veloman-yunkan #458)
|
||||
|
||||
* Server improvements :
|
||||
- Remove meta endpoints (@mgautier #669)
|
||||
- Add raw endpoints to get the raw content of a zim (@mgautierfr #646)
|
||||
- Add details on 404 error pages (@soumyankar #490)
|
||||
- Fix headbar insertion when `<head>` tag has attributes (@kelson42 #440)
|
||||
- Better headbar insertion (after charset definition) (@kelson42 #442)
|
||||
|
||||
* New OPDS Stream v2 :
|
||||
- Add a list of categories (@veloman-yunkan)
|
||||
- Support for partial entries (@veloman-yunkan #602)
|
||||
- Support multiple icons size in the OPDS stream (@veloman-yunkan #577 #630)
|
||||
- Add language endpoint to catalog (@veloman-yunkan #553)
|
||||
- Add illustration API to get the illustration of a book (@mgautierfr #645)
|
||||
- OPDS search can now filter books by category (@veloman-yunkan #459)
|
||||
|
||||
* Library improvements :
|
||||
- Allow the libray to be live reloaded when the library.xml changes (@veloman-yunkan #636)
|
||||
- Properly handle removing of book from the library (@veloman-yunkan #485)
|
||||
- Use xapian to search for books in the library (@veloman-yunkan #460, #488)
|
||||
|
||||
* Added methods/functions :
|
||||
- Fix `fileExist` and introduce `fileReadable` (@juuz0 #668)
|
||||
- Add `getVersions` and `printVersions` functions (@kelson42 #665)
|
||||
- Add `getNetworkInterfaces()` and `getBestPublicIP()` functions (@juuz0 #622)
|
||||
- Add `get_zimid()` method to the search result (@maneeshpm #510)
|
||||
|
||||
* Various improvements :
|
||||
- Better secret value for aria2c rpc (@juuz0 #666)
|
||||
- Avoid duplicated Archive/Reader in the Searcher (@veloman-yunkan #648)
|
||||
- Add basic documentation (@mgautierfr #640)
|
||||
- Do not use Reader internally (@maneeshpm #536 #576)
|
||||
- Remove dependency headers from our public headers (@mgautierfr #574)
|
||||
- Downloader now don't write metalink on the filesystem (@kelson42 #502)
|
||||
- Support opening a zim file using a fd (@veloman-yukan #429)
|
||||
- Use C++11 std::thread instead of pthread (@mgautierfr #445)
|
||||
- [READER] Do not crash if zim file has no `Counter` metadata (@mgautierfr #449)
|
||||
- Ensure libzim dependency is compiled with xapian (@mgautierfr #434)
|
||||
- Support video and audio mimetype in `getMediaCount` (@kelson42 #439)
|
||||
- Better parsing of the counterMap (@kelson42 #437)
|
||||
- Adapt libkiwix to libzim 7.0.0 (@mgautierfr #428)
|
||||
- Remove deprecated methods (@mgautierfr)
|
||||
- CI: Build package for Ubuntu Hirsute, Impish and Jammy (@legoktm #431 #568) and remove Groovy
|
||||
- Fix compilation for FreeBSD (@swills g#432)
|
||||
- Many fixes and improvement (@MananJethwany, @maneeshpm, @veloman-yunkan, @mgautierfr)
|
||||
|
||||
kiwix-lib 9.4.1
|
||||
===============
|
||||
|
||||
* Fix `M/Counter` parsing.
|
||||
* [SERVER] Adjust body padding-top for taskbar
|
||||
* Fix potential crash when stoping a server not started.
|
||||
* Various fix in build system and the CI.
|
||||
|
||||
kiwix-lib 9.4.0
|
||||
===============
|
||||
|
||||
* [SERVER] Make the headers handling case insensitive.
|
||||
* [SERVER] Make server answer 204 http status code for empty search
|
||||
* [PACKAGING] Made CI build deb packages.
|
||||
* [SERVER] Add a way to prevent taskbar and external link bloquer at article
|
||||
level.
|
||||
* Fix meson file to be compatible with meson 0.45
|
||||
* [SERVER] Update search requests to use pageStart/pageLength instead of
|
||||
pageStart/pageEnd arguments.
|
||||
* [SERVER] Set a fixed favicon size in the main page.
|
||||
* [SERVER] Refactor the response system code to better handling future new
|
||||
libzim api.
|
||||
* Fix segmentation fault around exchange with aria2 process making
|
||||
kiwix-desktop crash at exit.
|
||||
|
||||
kiwix-lib 9.3.1
|
||||
===============
|
||||
|
||||
* Fix handling of samba path on windows.
|
||||
* Do not include `kiwix_config.h` in public header.
|
||||
* Fix compilation with libmicrohttpd v0.97.1
|
||||
* Increase default test timeout to 160seconds/test.
|
||||
* Add automatic debian packaging.
|
||||
* Use non-minified version of jquery-ui.js
|
||||
* Pass `-latomic` compile option for sh4 architecture.
|
||||
* Make mesion install `kiwix-compile-resources` man page.
|
||||
|
||||
kiwix-lib 9.3.0
|
||||
===============
|
||||
|
||||
* Add a thread safe method to search suggestions.
|
||||
Old methods are now deprecated.
|
||||
|
||||
kiwix-lib 9.2.3
|
||||
===============
|
||||
|
||||
* Add test on byte-range
|
||||
* Fix compilation on bionic and windows.
|
||||
* Allow building using debian packaged kainjow-mustache
|
||||
* Pass `-latomic` compile option for architectures that need it
|
||||
|
||||
kiwix-lib 9.2.2
|
||||
===============
|
||||
|
||||
* Fix handling on empty content in byte range management (wrong assert)
|
||||
|
||||
kiwix-lib 9.2.1
|
||||
===============
|
||||
|
||||
* Fix support of byte range request.
|
||||
|
||||
kiwix-lib 9.2
|
||||
=============
|
||||
|
||||
* Add tests
|
||||
* Refactoring server code.
|
||||
* [SERVER] Add HEAD, Etag and If-None-Match support.
|
||||
* [SERVER] Compress opds catalog answers.
|
||||
|
||||
kiwix-lib 9.1.2
|
||||
===============
|
||||
|
||||
* Do not use the pathToSave if it is empty.
|
||||
|
||||
kiwix-lib 9.1.1
|
||||
===============
|
||||
|
||||
* Fix the detection of the dataDirectory on windows.
|
||||
|
||||
kiwix-lib 9.1.0
|
||||
===============
|
||||
|
||||
* [JAVA] Add a method to get the size of an article.
|
||||
* Add a new method to the libray to get the book by path.
|
||||
* Add a option to make the server blocks external link.
|
||||
Links are intercepted by js an redirected to a "portail" page.
|
||||
* [ODPS] Correctly handle book's articleCount and mediaCount.
|
||||
|
||||
kiwix-lib 9.0.1
|
||||
===============
|
||||
|
||||
* [JAVA] Use a long to store the offset of an article in the zim file instead
|
||||
of an int.
|
||||
|
||||
kiwix-lib 9.0.0
|
||||
===============
|
||||
|
||||
* [OPDS] Correctly set the id of the OPDS stream.
|
||||
* [OPDS] Do not try to filter the catalog if no filter field is given in the
|
||||
request.
|
||||
* [WINDOWS] Correctly convert path to wide chars when opening the library.xml
|
||||
* [LIBRARY] Remove the function the read file using a native path.
|
||||
All path must be utf8, no need to pass a native path along the utf8 path.
|
||||
* [TEST] Fix tests using the main function of gtest instead of custom one.
|
||||
* [CI] Move to github CI instead of Travis.
|
||||
* The `Book::update` method always update the book's fields. Even if they are
|
||||
not empty.
|
||||
* [JAVA] Add wrapping around the library manager (opds parsing)
|
||||
* [ARIA2] Add api option to start download with option (destination folder)
|
||||
* [OPDS] Fixes about opds parsing, generation (missing attributes)
|
||||
and requesting (server)
|
||||
* Add methods on `Book` to get specific tag values (was on `Reader` only)
|
||||
* Add flavour attribute to `Book`
|
||||
* Fix opensearch description.
|
||||
* Trust the given library.xml (by default) instead of reading the value from
|
||||
the zim files.
|
||||
* [OPDS] Be able to filter the content by name or size.
|
||||
* [WINDOWS] Fix launching subcommand when there is spaces in the path.
|
||||
|
||||
kiwix-lib 8.2.2
|
||||
===============
|
||||
|
||||
* Improve a few compilation scripts
|
||||
|
||||
kiwix-lib 8.2.1
|
||||
===============
|
||||
|
||||
* Reintroduce kiwix-serve taskbar
|
||||
|
||||
kiwix-lib 8.2.0
|
||||
===============
|
||||
|
||||
* More debug information if aria2c command fails
|
||||
* Allow to set kiwix-serve port
|
||||
* Better (dead) bookmarks mgmt
|
||||
|
||||
kiwix-lib 8.1.0
|
||||
===============
|
||||
|
||||
* Fix pathTools manipulation.
|
||||
* Add missing implementation of getArticleCount and getMediaCount on android.
|
||||
* Correctly convert windows path to utf8.
|
||||
* Add code coverage in the CI
|
||||
|
||||
kiwix-lib 8.0.1
|
||||
===============
|
||||
|
||||
* Fix join function
|
||||
|
||||
kiwix-lib 8.0.0
|
||||
===============
|
||||
|
||||
* Add new methods to get all (and new) metadata from the zim file.
|
||||
* Add methods to get the value of a specific tag.
|
||||
* [API Change] Convert tags value to the new convention.
|
||||
* [API Change] Rename `getMatatag` method to `getMetadata`
|
||||
* [ABI Change] Correctly detect executable path in appimage.
|
||||
|
||||
kiwix-lib 7.0.0
|
||||
===============
|
||||
|
||||
* [API break] Add a argument to kiwix-serve to specify the library to use.
|
||||
|
||||
kiwix-lib 6.0.4
|
||||
===============
|
||||
|
||||
* Fix HTML rendering of the search result if there is no result.
|
||||
* Do not crash at html rendering if request ask for 0 results (start == end)
|
||||
* Correctly find the executable path if we are using AppImage
|
||||
|
||||
kiwix-lib 6.0.3
|
||||
===============
|
||||
|
||||
* force one column suggestion in kiwix-serve suggestions
|
||||
* fix fulltext search link in suggestions
|
||||
* UI fixes in kiwix-serve rendering
|
||||
|
||||
kiwix-lib 6.0.2
|
||||
===============
|
||||
|
||||
* Correctly set the groupId in the pom file.
|
||||
|
||||
kiwix-lib 6.0.1
|
||||
===============
|
||||
|
||||
* Generate the pom file for android/maven
|
||||
|
||||
kiwix-lib 6.0.0
|
||||
===============
|
||||
|
||||
* Move the server code in kiwix-lib (from kiwix-serve).
|
||||
* Add unit test on regex functions.
|
||||
* Fix computerAbsolutePath (thread safe, memory leak).
|
||||
* Correctly set the book's path as valid if we construct the book from a
|
||||
reader.
|
||||
* [JNI] Add a method to know if a article is a redirection.
|
||||
* Do not embed the gtest dependency.
|
||||
* [JNI] Add a constructor to JNIKiwixString.
|
||||
* Change order of search of the favicon urls.
|
||||
* Clean a lot of unecessary includes in headers. (potential "API break")
|
||||
|
||||
kiwix-lib 5.2.0
|
||||
===============
|
||||
|
||||
* kiwix-serve integration (as a seperated process).
|
||||
* Fix crash in the suggestion search.
|
||||
* Better API to filter the library books.
|
||||
* New kiwix-lib application for android. (.aar)
|
||||
* Use ReLinker to link with libkiwix.so in android.
|
||||
* Correctly set the verbosity of zim search.
|
||||
|
||||
kiwix-lib 5.1.0
|
||||
===============
|
||||
|
||||
* Add function to pause, resume and stop downloads.
|
||||
* Add zim's tags in the opds stream.
|
||||
* Addapt to new libzim 5.0.0 API.
|
||||
|
||||
kiwix-lib 5.0.0
|
||||
===============
|
||||
|
||||
* Remove error message when trying to open an wrong zim file.
|
||||
* Rewrite `makeTmpDirectory` to not use uuid functions on windows.
|
||||
* [API break] Remove `getNetworkInterfaces` and `getBestPublicIp`.
|
||||
* Remove rpath
|
||||
* Detect infinite (and too long) redirect loops.
|
||||
|
||||
kiwix-lib 4.1.0
|
||||
===============
|
||||
|
||||
* Allow the library to be filtered by tags.
|
||||
* Fix language mapping.
|
||||
* Update README about mustache dependency.
|
||||
|
||||
kiwix-lib 4.0.1
|
||||
===============
|
||||
|
||||
* Fix "maybe uninitialize variable" issue.
|
||||
* Ensure path are stored correctly (absolute path) in the library.
|
||||
* [CI] Use the new deps archive xz
|
||||
|
||||
kiwix-lib 4.0.0
|
||||
===============
|
||||
|
||||
* [API break] Remove support for external index.
|
||||
* Move to the mustache templating system instead of ctpp2.
|
||||
* Make meson.build works for meson>=0.43.0
|
||||
* [API break] Move the basic tools from the `common` directory to `tools`.
|
||||
|
||||
kiwix-lib 3.1.1
|
||||
===============
|
||||
|
||||
* The OPDS feed book's date must be the date of the book, not the date of the
|
||||
feed generation.
|
||||
* Convert the standard opds date to our format (YYYY-MM-DD)
|
||||
* Remove duplicate language attribute in the libxml dumper.
|
||||
* Create the datadirectory to not fail to write a file in a non-existent
|
||||
directory
|
||||
|
||||
kiwix-lib 3.1.0
|
||||
===============
|
||||
|
||||
* Add a method to get the favicon url of book (if available).
|
||||
* Move dump code of library.xml in a specific class.
|
||||
* Add a first support to bookmarks
|
||||
|
||||
kiwix-lib 3.0.3
|
||||
===============
|
||||
|
||||
@@ -557,7 +5,6 @@ kiwix-lib 3.0.3
|
||||
('eng').
|
||||
* Correctly write the 'ArticleCount' and 'MediaCount' in the library.xml.
|
||||
* Correctly fill the book size for the zim file size.
|
||||
* Fix launch of aria2c.
|
||||
|
||||
kiwix-lib 3.0.2
|
||||
===============
|
||||
|
||||
212
README.md
212
README.md
@@ -1,220 +1,121 @@
|
||||
Libkiwix
|
||||
========
|
||||
Kiwix library
|
||||
=============
|
||||
|
||||
The Libkiwix provides the [Kiwix](https://kiwix.org) software suite
|
||||
core. It contains the code shared by all Kiwix ports (Windows,
|
||||
GNU/Linux, macOS, Android, iOS, ...).
|
||||
|
||||
[](https://download.kiwix.org/release/libkiwix/)
|
||||
[](https://github.com/kiwix/libkiwix/wiki/Repology)
|
||||
[](https://github.com/kiwix/libkiwix/actions?query=branch%3Amain)
|
||||
[](https://libkiwix.readthedocs.org/en/latest/?badge=latest)
|
||||
[](https://www.codefactor.io/repository/github/kiwix/libkiwix)
|
||||
[](https://codecov.io/gh/kiwix/libkiwix)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||
The Kiwix library provides the Kiwix software core. It contains the
|
||||
code shared by all Kiwix ports (Windows, Linux, OSX, Android, ...).
|
||||
|
||||
Disclaimer
|
||||
----------
|
||||
|
||||
This document assumes you have a little knowledge about software
|
||||
compilation. If you experience difficulties with the dependencies or
|
||||
with the Libkiwix compilation itself, we recommend to have a look to
|
||||
[kiwix-build](https://github.com/kiwix/kiwix-build).
|
||||
with the Kiwix libary compilation itself, we recommend to have a look
|
||||
to [kiwix-build](https://github.com/kiwix/kiwix-build).
|
||||
|
||||
Preamble
|
||||
--------
|
||||
|
||||
Although the Libkiwix can be (cross-)compiled on/for many systems, the
|
||||
following documentation explains how to do it on POSIX ones. It is
|
||||
primarily thought for GNU/Linux systems and has been tested on recent
|
||||
releases of Ubuntu and Fedora.
|
||||
Although the Kiwix library can be (cross-)compiled on/for many
|
||||
sytems, the following documentation explains how to do it on POSIX
|
||||
ones. It is primarly thought for GNU/Linux systems and has been tested
|
||||
on recent releases of Ubuntu and Fedora.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
The Libkiwix relies on many third party software libraries. They are
|
||||
prerequisites to the Libkiwix compilation. Following libraries need to
|
||||
be available:
|
||||
* [ICU](https://site.icu-project.org/) (package `libicu-dev` on Ubuntu)
|
||||
* [ZIM](https://openzim.org/) (package `libzim-dev` on Ubuntu)
|
||||
* [Pugixml](https://pugixml.org/) (package `libpugixml-dev` on Ubuntu)
|
||||
* [Mustache](https://github.com/kainjow/Mustache) (Just copy the
|
||||
header `mustache.hpp` somewhere it can be found by the compiler and/or
|
||||
set CPPFLAGS with correct `-I` option). Use Mustache version 4.1 or above.
|
||||
* [Libcurl](https://curl.se/libcurl) (`libcurl4-gnutls-dev`, `libcurl4-nss-dev` or `libcurl4-openssl-dev` on Ubuntu)
|
||||
* [Microhttpd](https://www.gnu.org/software/libmicrohttpd) (package `libmicrohttpd-dev` on Ubuntu)
|
||||
* [Zlib](https://zlib.net/) (package `zlib1g-dev` on Ubuntu)
|
||||
The Kiwix library relies on many third parts software libraries. They
|
||||
are prerequisites to the Kiwix library compilation. Following
|
||||
libraries need to be available:
|
||||
|
||||
To test the code:
|
||||
* [Google Test](https://github.com/google/googletest) (package `googletest` on Ubuntu)
|
||||
|
||||
The following dependency needs to be available at runtime:
|
||||
* [Aria2](https://aria2.github.io/) (package `aria2` on Ubuntu)
|
||||
* ICU ................................... http://site.icu-project.org/
|
||||
(package libicu-dev on Ubuntu)
|
||||
* ZIM ........................................ http://www.openzim.org/
|
||||
(package libzim-dev on Ubuntu)
|
||||
* Pugixml ........................................ http://pugixml.org/
|
||||
(package libpugixml-dev on Ubuntu)
|
||||
* ctpp2 ........................................ http://ctpp.havoc.ru/
|
||||
(package libctpp2-dev on Ubuntu)
|
||||
* Xapian ......................................... https://xapian.org/
|
||||
(package libxapian-dev on Ubuntu)
|
||||
* libaria2 .................................. https://aria2.github.io/
|
||||
(no package on Ubuntu)
|
||||
|
||||
These dependencies may or may not be packaged by your operating
|
||||
system. They may also be packaged but only in an older version. The
|
||||
compilation script will tell you if one of them is missing or too old.
|
||||
In the worst case, you will have to download and compile bleeding edge
|
||||
In the worse case, you will have to download and compile bleeding edge
|
||||
version by hand.
|
||||
|
||||
If you want to install these dependencies locally, then use the
|
||||
`libkiwix` directory as install prefix.
|
||||
kiwix-lib directory as install prefix.
|
||||
|
||||
If you compile ctpp2 from source and want to compile the Kiwix library
|
||||
statically then you will probably need to rename ctpp2 static library
|
||||
from ctpp2-st.a to ctpp2.a.
|
||||
|
||||
Environment
|
||||
-------------
|
||||
|
||||
The Libkiwix builds using [Meson](https://mesonbuild.com/) version
|
||||
0.45 or higher. Meson relies itself on Ninja, pkg-config and few other
|
||||
The Kiwix library builds using [Meson](http://mesonbuild.com/) version
|
||||
0.39 or higher. Meson relies itself on Ninja, pkg-config and few other
|
||||
compilation tools.
|
||||
|
||||
Install first the few common compilation tools:
|
||||
* [Meson](https://mesonbuild.com/)
|
||||
* [Ninja](https://ninja-build.org/)
|
||||
* [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/)
|
||||
* Meson
|
||||
* Ninja
|
||||
* Pkg-config
|
||||
|
||||
These tools should be packaged if you use a cutting edge operating
|
||||
system. If not, have a look to the [Troubleshooting](#Troubleshooting)
|
||||
section.
|
||||
system. If not, have a look to the "Troubleshooting" section.
|
||||
|
||||
Compilation
|
||||
-----------
|
||||
|
||||
Once all dependencies are installed, you can compile the Libkiwix
|
||||
Once all dependencies are installed, you can compile the Kiwix library
|
||||
with:
|
||||
```bash
|
||||
```
|
||||
meson . build
|
||||
ninja -C build
|
||||
```
|
||||
|
||||
By default, it will compile dynamic linked libraries. All binary files
|
||||
will be created in the `build` directory created automatically by
|
||||
will be created in the "build" directory created automatically by
|
||||
Meson. If you want statically linked libraries, you can add
|
||||
`--default-library=static` option to the Meson command.
|
||||
|
||||
Depending of you system, `ninja` may be called `ninja-build`.
|
||||
|
||||
The android wrapper uses deprecated methods of libkiwix so it cannot be compiled
|
||||
with `werror=true` (the default). So you must pass `-Dwerror=false` to meson:
|
||||
|
||||
```bash
|
||||
meson . build -Dwrapper=android -Dwerror=false
|
||||
ninja -C build
|
||||
```
|
||||
|
||||
Static files compilation
|
||||
------------------------
|
||||
|
||||
Libkiwix has a few static files 'compiled' within the binary
|
||||
code. This is mostly Javascript/HTML/pictures necessary for the HTTP
|
||||
daemon.
|
||||
|
||||
These static files are available in the `static` directory and are
|
||||
compiled by custom Python code available in this repository `scripts`
|
||||
directory. This happens automatically at compilation time without any
|
||||
additional command to run.
|
||||
|
||||
To avoid HTTP caching issues, the URLs (to the static content) are
|
||||
appended with a `cacheid` parameter (this is called "cache
|
||||
busting"). This `cacheid` value derived from the
|
||||
[sha1sum](https://en.wikipedia.org/wiki/Sha1sum) of each targeted
|
||||
static file. As a consequence, each time you change a static file, the
|
||||
corresponding `cacheid` value will change.
|
||||
|
||||
To properly test this feature, this `cacheid` needs to be added
|
||||
manually to the automated tests and has to be commited. After
|
||||
modifying the needed static file, [run the automated
|
||||
tests](#Testing). They will fail, but the inspection of the testing
|
||||
log will give you the new `cacheid` value(s). Finally update
|
||||
`test/server.cpp` with the appropriate `cacheid` value(s) which have
|
||||
changed.
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
To run the automated tests:
|
||||
```bash
|
||||
cd build
|
||||
meson test
|
||||
```
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
If you want to install the Libkiwix and the headers you just have
|
||||
If you want to install the Kiwix library and the headers you just have
|
||||
compiled on your system, here we go:
|
||||
```bash
|
||||
|
||||
```
|
||||
ninja -C build install
|
||||
```
|
||||
|
||||
You might need to run the command as root (or using `sudo`), depending
|
||||
You might need to run the command as root (or using 'sudo'), depending
|
||||
where you want to install the libraries. After the installation
|
||||
succeeded, you may need to run `ldconfig` (as `root`).
|
||||
succeeded, you may need to run ldconfig (as root).
|
||||
|
||||
Uninstallation
|
||||
--------------
|
||||
------------
|
||||
|
||||
If you want to uninstall the Kiwix library:
|
||||
```bash
|
||||
|
||||
```
|
||||
ninja -C build uninstall
|
||||
```
|
||||
|
||||
Like for the installation, you might need to run the command as `root`
|
||||
(or using `sudo`).
|
||||
|
||||
Custom Index Page
|
||||
-----------------
|
||||
|
||||
to use custom welcome page mention `customIndexPage` argument in `kiwix::internalServer()` or use `kiwix::server->setCustomIndexTemplate()`.
|
||||
(note - while using custom html file please mention all external links as absolute path.)
|
||||
|
||||
to create a HTML template with custom JS you need to have a look at various OPDS based endpoints as mentioned [here](https://wiki.kiwix.org/wiki/OPDS) to load books.
|
||||
|
||||
To use JS provided by kiwix-serve you can use the following template to start with ->
|
||||
|
||||
```
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title><-- Custom Tittle --></title>
|
||||
<script src="{{root}}/skin/isotope.pkgd.min.js" defer></script>
|
||||
<script src="{{root}}/skin/iso6391To3.js"></script>
|
||||
<script type="text/javascript" src="{{root}}/skin/index.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
- To get books listed using `index.js` add - `<div class="book__list"></div>` under body tag.
|
||||
- To get number of books listed add - `<h3 class="kiwixHomeBody__results"></h3>` under body tag.
|
||||
- To add language select box add - `<select id="languageFilter"></select>` under body tag.
|
||||
- To add category select box add - `<select id="categoryFilter"></select>` under body tag.
|
||||
- To add search box for books use following form -
|
||||
```
|
||||
<form id='kiwixSearchForm'>
|
||||
<input type="text" name="q" placeholder="Search" id="searchFilter" class='kiwixSearch filter'>
|
||||
<input type="submit" class="kiwixButton" value="Search"/>
|
||||
</form>
|
||||
```
|
||||
|
||||
|
||||
If you compile manually Libmicrohttpd, you might need to compile it
|
||||
without GNU TLS, a bug here will impeach further compilation
|
||||
otherwise.
|
||||
|
||||
If the compilation still fails, you might need to get a more recent
|
||||
version of a dependency than the one packaged by your Linux
|
||||
distribution. Try then with a source tarball distributed by the
|
||||
problematic upstream project or even directly from the source code
|
||||
repository.
|
||||
Like for the installation, you might need to run the command as root
|
||||
(or using 'sudo').
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
If you need to install Meson "manually":
|
||||
```bash
|
||||
```
|
||||
virtualenv -p python3 ./ # Create virtualenv
|
||||
source bin/activate # Activate the virtualenv
|
||||
pip3 install meson # Install Meson
|
||||
@@ -222,7 +123,7 @@ hash -r # Refresh bash paths
|
||||
```
|
||||
|
||||
If you need to install Ninja "manually":
|
||||
```bash
|
||||
```
|
||||
git clone git://github.com/ninja-build/ninja.git
|
||||
cd ninja
|
||||
git checkout release
|
||||
@@ -232,8 +133,13 @@ cp ninja ../bin
|
||||
cd ..
|
||||
```
|
||||
|
||||
If the compilation still fails, you might need to get a more recent
|
||||
version of a dependency than the one packaged by your Linux
|
||||
distribution. Try then with a source tarball distributed by the
|
||||
problematic upstream project or even directly from the source code
|
||||
repository.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
[GPLv3](https://www.gnu.org/licenses/gpl-3.0) or later, see
|
||||
[COPYING](COPYING) for more details.
|
||||
GPLv3 or later, see COPYING for more details.
|
||||
|
||||
5
debian/changelog
vendored
5
debian/changelog
vendored
@@ -1,5 +0,0 @@
|
||||
libkiwix (0.0.0) unstable; urgency=medium
|
||||
|
||||
* Initial release
|
||||
|
||||
-- Kunal Mehta <legoktm@debian.org> Wed, 08 Jul 2020 18:12:32 -0700
|
||||
47
debian/control
vendored
47
debian/control
vendored
@@ -1,47 +0,0 @@
|
||||
Source: libkiwix
|
||||
Priority: optional
|
||||
Maintainer: Kiwix team <kiwix@kiwix.org>
|
||||
Build-Depends: debhelper-compat (= 13),
|
||||
meson,
|
||||
pkgconf,
|
||||
libzim-dev (>= 9.0), libzim-dev (<< 10.0),
|
||||
libcurl4-gnutls-dev,
|
||||
libicu-dev,
|
||||
libgtest-dev,
|
||||
libkainjow-mustache-dev,
|
||||
libmicrohttpd-dev,
|
||||
libpugixml-dev,
|
||||
zlib1g-dev
|
||||
Standards-Version: 4.5.0
|
||||
Section: libs
|
||||
Homepage: https://github.com/kiwix/libkiwix
|
||||
Rules-Requires-Root: no
|
||||
|
||||
Package: libkiwix-dev
|
||||
Section: libdevel
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Depends: libkiwix14 (= ${binary:Version}), ${misc:Depends}, python3,
|
||||
libzim-dev (>= 9.0), libzim-dev (<< 10.0),
|
||||
libicu-dev,
|
||||
libpugixml-dev,
|
||||
libcurl4-gnutls-dev,
|
||||
libmicrohttpd-dev,
|
||||
zlib1g-dev
|
||||
Description: library of common code for Kiwix (development)
|
||||
Kiwix is an offline Wikipedia reader. libkiwix provides the
|
||||
software core for Kiwix, and contains the code shared by all
|
||||
Kiwix ports (Windows, Linux, OSX, Android, etc.).
|
||||
.
|
||||
This package contains development files.
|
||||
|
||||
Package: libkiwix14
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, aria2
|
||||
Conflicts: libkiwix0, libkiwix3, libkiwix9, libkiwix10, libkiwix11, libkiwix12, libkiwix13
|
||||
Replaces: libkiwix0, libkiwix3, libkiwix9, libkiwix10, libkiwix11, libkiwix12, libkiwix13
|
||||
Description: library of common code for Kiwix
|
||||
Kiwix is an offline Wikipedia reader. libkiwix provides the
|
||||
software core for Kiwix, and contains the code shared by all
|
||||
Kiwix ports (Windows, Linux, OSX, Android, etc.).
|
||||
1
debian/copyright
vendored
1
debian/copyright
vendored
@@ -1 +0,0 @@
|
||||
See COPYING in the repository root.
|
||||
4
debian/libkiwix-dev.install
vendored
4
debian/libkiwix-dev.install
vendored
@@ -1,4 +0,0 @@
|
||||
usr/include
|
||||
usr/lib/*/libkiwix.so
|
||||
usr/lib/*/pkgconfig
|
||||
usr/bin
|
||||
2
debian/libkiwix-dev.manpages
vendored
2
debian/libkiwix-dev.manpages
vendored
@@ -1,2 +0,0 @@
|
||||
usr/share/man/man1/kiwix-compile-resources.1*
|
||||
usr/share/man/man1/kiwix-compile-i18n.1*
|
||||
1
debian/libkiwix14.install
vendored
1
debian/libkiwix14.install
vendored
@@ -1 +0,0 @@
|
||||
usr/lib/*/libkiwix.so.*
|
||||
8
debian/rules
vendored
8
debian/rules
vendored
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/make -f
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
|
||||
%:
|
||||
dh $@ --buildsystem=meson
|
||||
|
||||
override_dh_auto_test:
|
||||
dh_auto_test -- -t 3
|
||||
1
debian/source/format
vendored
1
debian/source/format
vendored
@@ -1 +0,0 @@
|
||||
3.0 (native)
|
||||
2
docs/.gitignore
vendored
2
docs/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
api
|
||||
xml
|
||||
68
docs/conf.py
68
docs/conf.py
@@ -1,68 +0,0 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'libkiwix'
|
||||
copyright = '2022, libkiwix-team'
|
||||
author = 'libkiwix-team'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'breathe',
|
||||
'exhale'
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
breathe_projects = {
|
||||
"libkiwix": "./xml"
|
||||
}
|
||||
breathe_default_project = 'libkiwix'
|
||||
|
||||
exhale_args = {
|
||||
"containmentFolder": "./api",
|
||||
"rootFileName": "ref_api.rst",
|
||||
"rootFileTitle": "Reference API",
|
||||
"doxygenStripFromPath":"..",
|
||||
"treeViewIsBootstrap": True,
|
||||
"createTreeView" : True,
|
||||
"exhaleExecutesDoxygen": True,
|
||||
"exhaleDoxygenStdin": "INPUT = ../include"
|
||||
}
|
||||
|
||||
primary_domain = 'cpp'
|
||||
|
||||
highlight_language = 'cpp'
|
||||
@@ -1,14 +0,0 @@
|
||||
.. libkiwix documentation master file, created by
|
||||
sphinx-quickstart on Fri Jul 24 15:40:50 2020.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to libkiwix's documentation!
|
||||
==================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
usage
|
||||
api/ref_api
|
||||
@@ -1,7 +0,0 @@
|
||||
|
||||
sphinx = find_program('sphinx-build', native:true)
|
||||
|
||||
sphinx_target = run_target('doc',
|
||||
command: [sphinx, '-bhtml',
|
||||
meson.current_source_dir(),
|
||||
meson.current_build_dir()])
|
||||
@@ -1,3 +0,0 @@
|
||||
breathe
|
||||
exhale
|
||||
sphinx_rtd_theme
|
||||
@@ -1,15 +0,0 @@
|
||||
Libkiwix programming
|
||||
====================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
libkiwix is written in C++. To use the library, you need the include files of libkiwix have
|
||||
to link against libzim.
|
||||
|
||||
Errors are handled with exceptions. When something goes wrong, libkiwix throws an error,
|
||||
which is always derived from std::exception.
|
||||
|
||||
All classes are defined in the namespace kiwix.
|
||||
|
||||
libkiwix is a set of tools to manage zim files and provide some common functionnality.
|
||||
36
format_code.sh
Executable file
36
format_code.sh
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
files=(
|
||||
"include/library.h"
|
||||
"include/common/stringTools.h"
|
||||
"include/common/pathTools.h"
|
||||
"include/common/otherTools.h"
|
||||
"include/common/regexTools.h"
|
||||
"include/common/networkTools.h"
|
||||
"include/manager.h"
|
||||
"include/reader.h"
|
||||
"include/kiwix.h"
|
||||
"include/xapianSearcher.h"
|
||||
"include/searcher.h"
|
||||
"src/library.cpp"
|
||||
"src/android/kiwix.cpp"
|
||||
"src/android/org/kiwix/kiwixlib/JNIKiwixBool.java"
|
||||
"src/android/org/kiwix/kiwixlib/JNIKiwix.java"
|
||||
"src/android/org/kiwix/kiwixlib/JNIKiwixString.java"
|
||||
"src/android/org/kiwix/kiwixlib/JNIKiwixInt.java"
|
||||
"src/searcher.cpp"
|
||||
"src/common/pathTools.cpp"
|
||||
"src/common/regexTools.cpp"
|
||||
"src/common/otherTools.cpp"
|
||||
"src/common/networkTools.cpp"
|
||||
"src/common/stringTools.cpp"
|
||||
"src/xapianSearcher.cpp"
|
||||
"src/manager.cpp"
|
||||
"src/reader.cpp"
|
||||
)
|
||||
|
||||
for i in "${files[@]}"
|
||||
do
|
||||
echo $i
|
||||
clang-format -i -style=file $i
|
||||
done
|
||||
@@ -21,94 +21,62 @@
|
||||
#define KIWIX_BOOK_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include "common.h"
|
||||
|
||||
namespace pugi {
|
||||
class xml_node;
|
||||
}
|
||||
|
||||
namespace zim {
|
||||
class Archive;
|
||||
}
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
enum supportedIndexType { UNKNOWN, XAPIAN };
|
||||
|
||||
class OPDSDumper;
|
||||
class Reader;
|
||||
|
||||
/**
|
||||
* A class to store information about a book (a zim file)
|
||||
*/
|
||||
class Book
|
||||
{
|
||||
public: // types
|
||||
class Illustration
|
||||
{
|
||||
friend class Book;
|
||||
public:
|
||||
uint16_t width = 48;
|
||||
uint16_t height = 48;
|
||||
std::string mimeType;
|
||||
std::string url;
|
||||
|
||||
const std::string& getData() const;
|
||||
|
||||
private:
|
||||
mutable std::string data;
|
||||
mutable std::mutex mutex;
|
||||
};
|
||||
|
||||
typedef std::vector<std::shared_ptr<const Illustration>> Illustrations;
|
||||
|
||||
public: // functions
|
||||
public:
|
||||
Book();
|
||||
~Book();
|
||||
|
||||
bool update(const Book& other);
|
||||
void update(const zim::Archive& archive);
|
||||
void update(const Reader& reader);
|
||||
void updateFromXml(const pugi::xml_node& node, const std::string& baseDir);
|
||||
void updateFromOpds(const pugi::xml_node& node, const std::string& urlHost);
|
||||
std::string getHumanReadableIdFromPath() const;
|
||||
std::string getHumanReadableIdFromPath();
|
||||
|
||||
bool readOnly() const { return m_readOnly; }
|
||||
const std::string& getId() const { return m_id; }
|
||||
const std::string& getPath() const { return m_path; }
|
||||
bool isPathValid() const { return m_pathValid; }
|
||||
const std::string& getIndexPath() const { return m_indexPath; }
|
||||
const supportedIndexType& getIndexType() const { return m_indexType; }
|
||||
const std::string& getTitle() const { return m_title; }
|
||||
const std::string& getDescription() const { return m_description; }
|
||||
DEPRECATED const std::string& getLanguage() const { return m_language; }
|
||||
const std::string& getCommaSeparatedLanguages() const { return m_language; }
|
||||
const std::vector<std::string> getLanguages() const;
|
||||
const std::string& getLanguage() const { return m_language; }
|
||||
const std::string& getCreator() const { return m_creator; }
|
||||
const std::string& getPublisher() const { return m_publisher; }
|
||||
const std::string& getDate() const { return m_date; }
|
||||
const std::string& getUrl() const { return m_url; }
|
||||
const std::string& getName() const { return m_name; }
|
||||
std::string getCategory() const;
|
||||
const std::string& getTags() const { return m_tags; }
|
||||
std::string getTagStr(const std::string& tagName) const;
|
||||
bool getTagBool(const std::string& tagName) const;
|
||||
const std::string& getFlavour() const { return m_flavour; }
|
||||
const std::string& getOrigId() const { return m_origId; }
|
||||
const uint64_t& getArticleCount() const { return m_articleCount; }
|
||||
const uint64_t& getMediaCount() const { return m_mediaCount; }
|
||||
const uint64_t& getSize() const { return m_size; }
|
||||
DEPRECATED const std::string& getFavicon() const;
|
||||
DEPRECATED const std::string& getFaviconUrl() const;
|
||||
DEPRECATED const std::string& getFaviconMimeType() const;
|
||||
|
||||
Illustrations getIllustrations() const;
|
||||
std::shared_ptr<const Illustration> getIllustration(unsigned int size) const;
|
||||
|
||||
const std::string& getFavicon() const;
|
||||
const std::string& getFaviconMimeType() const { return m_faviconMimeType; }
|
||||
const std::string& getDownloadId() const { return m_downloadId; }
|
||||
|
||||
void setReadOnly(bool readOnly) { m_readOnly = readOnly; }
|
||||
void setId(const std::string& id) { m_id = id; }
|
||||
void setPath(const std::string& path);
|
||||
void setPathValid(bool valid) { m_pathValid = valid; }
|
||||
void setIndexPath(const std::string& indexPath);
|
||||
void setIndexType(supportedIndexType indexType) { m_indexType = indexType;}
|
||||
void setTitle(const std::string& title) { m_title = title; }
|
||||
void setDescription(const std::string& description) { m_description = description; }
|
||||
void setLanguage(const std::string& language) { m_language = language; }
|
||||
@@ -117,44 +85,39 @@ class Book
|
||||
void setDate(const std::string& date) { m_date = date; }
|
||||
void setUrl(const std::string& url) { m_url = url; }
|
||||
void setName(const std::string& name) { m_name = name; }
|
||||
void setFlavour(const std::string& flavour) { m_flavour = flavour; }
|
||||
void setTags(const std::string& tags) { m_tags = tags; }
|
||||
void setOrigId(const std::string& origId) { m_origId = origId; }
|
||||
void setArticleCount(uint64_t articleCount) { m_articleCount = articleCount; }
|
||||
void setMediaCount(uint64_t mediaCount) { m_mediaCount = mediaCount; }
|
||||
void setSize(uint64_t size) { m_size = size; }
|
||||
void setFavicon(const std::string& favicon) { m_favicon = favicon; }
|
||||
void setFaviconMimeType(const std::string& faviconMimeType) { m_faviconMimeType = faviconMimeType; }
|
||||
void setDownloadId(const std::string& downloadId) { m_downloadId = downloadId; }
|
||||
|
||||
private: // functions
|
||||
std::string getCategoryFromTags() const;
|
||||
const Illustration& getDefaultIllustration() const;
|
||||
|
||||
protected: // data
|
||||
protected:
|
||||
std::string m_id;
|
||||
std::string m_downloadId;
|
||||
std::string m_path;
|
||||
bool m_pathValid = false;
|
||||
bool m_pathValid;
|
||||
std::string m_indexPath;
|
||||
supportedIndexType m_indexType;
|
||||
std::string m_title;
|
||||
std::string m_description;
|
||||
std::string m_category;
|
||||
std::string m_language;
|
||||
std::string m_creator;
|
||||
std::string m_publisher;
|
||||
std::string m_date;
|
||||
std::string m_url;
|
||||
std::string m_name;
|
||||
std::string m_flavour;
|
||||
std::string m_tags;
|
||||
std::string m_origId;
|
||||
uint64_t m_articleCount = 0;
|
||||
uint64_t m_mediaCount = 0;
|
||||
bool m_readOnly = false;
|
||||
uint64_t m_size = 0;
|
||||
Illustrations m_illustrations;
|
||||
|
||||
// Used as the return value of getDefaultIllustration() when no default
|
||||
// illustration is found in the book
|
||||
static const Illustration missingDefaultIllustration;
|
||||
uint64_t m_articleCount;
|
||||
uint64_t m_mediaCount;
|
||||
bool m_readOnly;
|
||||
uint64_t m_size;
|
||||
mutable std::string m_favicon;
|
||||
std::string m_faviconUrl;
|
||||
std::string m_faviconMimeType;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_BOOKMARK_H
|
||||
#define KIWIX_BOOKMARK_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace pugi {
|
||||
class xml_node;
|
||||
}
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
class Book;
|
||||
/**
|
||||
* A class to store information about a bookmark (an article in a book)
|
||||
*/
|
||||
class Bookmark
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create an empty bookmark.
|
||||
*
|
||||
* Bookmark must be populated with `set*` methods
|
||||
*/
|
||||
Bookmark();
|
||||
|
||||
/**
|
||||
* Create a bookmark given a Book, a path and a title.
|
||||
*/
|
||||
Bookmark(const Book& book, const std::string& path, const std::string& title);
|
||||
|
||||
~Bookmark();
|
||||
|
||||
void updateFromXml(const pugi::xml_node& node);
|
||||
|
||||
const std::string& getBookId() const { return m_bookId; }
|
||||
const std::string& getBookTitle() const { return m_bookTitle; }
|
||||
const std::string& getBookName() const { return m_bookName; }
|
||||
const std::string& getBookFlavour() const { return m_bookFlavour; }
|
||||
const std::string& getUrl() const { return m_url; }
|
||||
const std::string& getTitle() const { return m_title; }
|
||||
const std::string& getLanguage() const { return m_language; }
|
||||
const std::string& getDate() const { return m_date; }
|
||||
|
||||
void setBookId(const std::string& bookId) { m_bookId = bookId; }
|
||||
void setBookTitle(const std::string& bookTitle) { m_bookTitle = bookTitle; }
|
||||
void setBookName(const std::string& bookName) { m_bookName = bookName; }
|
||||
void setBookFlavour(const std::string& bookFlavour) { m_bookFlavour = bookFlavour; }
|
||||
void setUrl(const std::string& url) { m_url = url; }
|
||||
void setTitle(const std::string& title) { m_title = title; }
|
||||
void setLanguage(const std::string& language) { m_language = language; }
|
||||
void setDate(const std::string& date) { m_date = date; }
|
||||
|
||||
protected:
|
||||
std::string m_bookId;
|
||||
std::string m_bookTitle;
|
||||
std::string m_bookName;
|
||||
std::string m_bookFlavour;
|
||||
std::string m_url;
|
||||
std::string m_title;
|
||||
std::string m_language;
|
||||
std::string m_date;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
namespace kiwix {
|
||||
|
||||
enum class IpMode { IPV4, IPV6, ALL, AUTO }; // AUTO: Server decides the protocol
|
||||
typedef zim::size_type size_type;
|
||||
typedef zim::offset_type offset_type;
|
||||
|
||||
|
||||
@@ -20,10 +20,13 @@
|
||||
#ifndef KIWIX_NETWORKTOOLS_H
|
||||
#define KIWIX_NETWORKTOOLS_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
std::map<std::string, std::string> getNetworkInterfaces();
|
||||
std::string getBestPublicIp();
|
||||
std::string download(const std::string& url);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
* Copyright 2014 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,18 +17,22 @@
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_VERSION_H
|
||||
#define KIWIX_VERSION_H
|
||||
#ifndef KIWIX_OTHERTOOLS_H
|
||||
#define KIWIX_OTHERTOOLS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
typedef std::vector<std::pair<std::string, std::string>> LibVersions;
|
||||
LibVersions getVersions();
|
||||
void printVersions(std::ostream& out = std::cout);
|
||||
void sleep(unsigned int milliseconds);
|
||||
std::string nodeToString(pugi::xml_node node);
|
||||
std::string converta2toa3(const std::string& a2code);
|
||||
}
|
||||
|
||||
#endif // KIWIX_VERSION_H
|
||||
#endif
|
||||
64
include/common/pathTools.h
Normal file
64
include/common/pathTools.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2011 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_PATHTOOLS_H
|
||||
#define KIWIX_PATHTOOLS_H
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
#include "stringTools.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool isRelativePath(const string& path);
|
||||
string computeAbsolutePath(const string path, const string relativePath);
|
||||
string computeRelativePath(const string path, const string absolutePath);
|
||||
string removeLastPathElement(const string path,
|
||||
const bool removePreSeparator = false,
|
||||
const bool removePostSeparator = false);
|
||||
string appendToDirectory(const string& directoryPath, const string& filename);
|
||||
|
||||
unsigned int getFileSize(const string& path);
|
||||
string getFileSizeAsString(const string& path);
|
||||
string getFileContent(const string& path);
|
||||
bool fileExists(const string& path);
|
||||
bool makeDirectory(const string& path);
|
||||
string makeTmpDirectory();
|
||||
bool copyFile(const string& sourcePath, const string& destPath);
|
||||
string getLastPathElement(const string& path);
|
||||
string getExecutablePath();
|
||||
string getCurrentDirectory();
|
||||
string getDataDirectory();
|
||||
bool writeTextFile(const string& path, const string& content);
|
||||
#endif
|
||||
@@ -20,11 +20,17 @@
|
||||
#ifndef KIWIX_REGEXTOOLS_H
|
||||
#define KIWIX_REGEXTOOLS_H
|
||||
|
||||
#include <unicode/regex.h>
|
||||
#include <unicode/ucnv.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
bool matchRegex(const std::string& content, const std::string& regex);
|
||||
std::string replaceRegex(const std::string& content,
|
||||
const std::string& replacement,
|
||||
const std::string& regex);
|
||||
std::string appendToFirstOccurence(const std::string& content,
|
||||
const std::string regex,
|
||||
const std::string& replacement);
|
||||
|
||||
#endif
|
||||
@@ -21,16 +21,22 @@
|
||||
#define KIWIX_STRINGTOOLS_H
|
||||
|
||||
#include <unicode/unistr.h>
|
||||
#include <unicode/locid.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "pathTools.h"
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
#ifndef __ANDROID__
|
||||
|
||||
std::string beautifyInteger(uint64_t number);
|
||||
std::string beautifyFileSize(uint64_t number);
|
||||
void printStringInHexadecimal(const char* s);
|
||||
void printStringInHexadecimal(icu::UnicodeString s);
|
||||
void stringReplacement(std::string& str,
|
||||
@@ -38,37 +44,23 @@ void stringReplacement(std::string& str,
|
||||
const std::string& newStr);
|
||||
std::string encodeDiples(const std::string& str);
|
||||
|
||||
#endif
|
||||
|
||||
std::string removeAccents(const std::string& text);
|
||||
void loadICUExternalTables();
|
||||
|
||||
class ICULanguageInfo
|
||||
{
|
||||
public:
|
||||
explicit ICULanguageInfo(const std::string& langCode);
|
||||
|
||||
std::string iso3Code() const;
|
||||
std::string selfName() const;
|
||||
|
||||
private:
|
||||
const icu::Locale locale;
|
||||
};
|
||||
|
||||
std::string escapeForJSON(const std::string& s, bool escapeQuote = true);
|
||||
|
||||
/* urlEncode() is the equivalent of JS encodeURIComponent(), with the only
|
||||
* difference that the slash (/) symbol is NOT encoded. */
|
||||
std::string urlEncode(const std::string& value);
|
||||
std::string urlEncode(const std::string& value, bool encodeReserved = false);
|
||||
std::string urlDecode(const std::string& value, bool component = false);
|
||||
|
||||
std::string join(const std::vector<std::string>& list, const std::string& sep);
|
||||
std::vector<std::string> split(const std::string&, const std::string&);
|
||||
std::vector<std::string> split(const char*, const char*);
|
||||
std::vector<std::string> split(const std::string&, const char*);
|
||||
std::vector<std::string> split(const char*, const std::string&);
|
||||
|
||||
std::string ucAll(const std::string& word);
|
||||
std::string lcAll(const std::string& word);
|
||||
std::string ucFirst(const std::string& word);
|
||||
std::string lcFirst(const std::string& word);
|
||||
|
||||
/* This function is broken, related Github issue
|
||||
* https://github.com/kiwix/libkiwix/issues/1188 */
|
||||
std::string toTitle(const std::string& word);
|
||||
|
||||
std::string normalize(const std::string& word);
|
||||
@@ -85,19 +77,7 @@ T extractFromString(const std::string& str) {
|
||||
std::istringstream iss(str);
|
||||
T ret;
|
||||
iss >> ret;
|
||||
if(iss.fail() || !iss.eof()) {
|
||||
throw std::invalid_argument("no conversion");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string extractFromString(const std::string& str);
|
||||
|
||||
bool startsWith(const std::string& base, const std::string& start);
|
||||
|
||||
std::string stripSuffix(const std::string& str, const std::string& suffix);
|
||||
|
||||
std::vector<std::string> getTitleVariants(const std::string& title);
|
||||
} //namespace kiwix
|
||||
#endif
|
||||
79
include/ctpp2/CTPP2VMStringLoader.hpp
Normal file
79
include/ctpp2/CTPP2VMStringLoader.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2013 Renaud Gaudin <reg@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _CTPP2_VM_STRING_LOADER_HPP__
|
||||
#define _CTPP2_VM_STRING_LOADER_HPP__ 1
|
||||
|
||||
#include <ctpp2/CTPP2VMLoader.hpp>
|
||||
#include <ctpp2/CTPP2Util.hpp>
|
||||
#include <ctpp2/CTPP2Exception.hpp>
|
||||
#include <ctpp2/CTPP2VMExecutable.hpp>
|
||||
#include <ctpp2/CTPP2VMInstruction.hpp>
|
||||
#include <ctpp2/CTPP2VMMemoryCore.hpp>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
@file VMStringLoader.hpp
|
||||
@brief Load program core from file
|
||||
*/
|
||||
|
||||
namespace CTPP // C++ Template Engine
|
||||
{
|
||||
// FWD
|
||||
struct VMExecutable;
|
||||
|
||||
/**
|
||||
@class VMStringLoader CTPP2VMStringLoader.hpp <CTPP2VMStringLoader.hpp>
|
||||
@brief Load program core from file
|
||||
*/
|
||||
class CTPP2DECL VMStringLoader:
|
||||
public VMLoader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
*/
|
||||
VMStringLoader(CCHAR_P rawContent, size_t rawContentSize);
|
||||
/**
|
||||
@brief Get ready-to-run program
|
||||
*/
|
||||
const VMMemoryCore * GetCore() const;
|
||||
|
||||
/**
|
||||
@brief A destructor
|
||||
*/
|
||||
~VMStringLoader() throw();
|
||||
private:
|
||||
/** Program core */
|
||||
VMExecutable * oCore;
|
||||
/** Ready-to-run program */
|
||||
VMMemoryCore * pVMMemoryCore;
|
||||
};
|
||||
|
||||
} // namespace CTPP
|
||||
#endif // _CTPP2_VM_STRING_LOADER_HPP__
|
||||
// End.
|
||||
@@ -23,9 +23,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <pthread.h>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <mutex>
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
@@ -44,14 +43,6 @@ class AriaError : public std::runtime_error {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A representation of a current download.
|
||||
*
|
||||
* `Download` is not thread safe. User must care to not call method on a
|
||||
* same download from different threads.
|
||||
* However, it is safe to use different `Download`s from different threads.
|
||||
*/
|
||||
|
||||
class Download {
|
||||
public:
|
||||
typedef enum { K_ACTIVE, K_WAITING, K_PAUSED, K_ERROR, K_COMPLETE, K_REMOVED, K_UNKNOWN } StatusResult;
|
||||
@@ -62,89 +53,16 @@ class Download {
|
||||
: mp_aria(p_aria),
|
||||
m_status(K_UNKNOWN),
|
||||
m_did(did) {};
|
||||
|
||||
/**
|
||||
* Update the status of the download.
|
||||
*
|
||||
* This call make an aria rpc call and is blocking.
|
||||
* Some download (started with a metalink) are in fact several downloads.
|
||||
* - A first one to download the metadlink.
|
||||
* - A second one to download the real file.
|
||||
*
|
||||
* If `follow` is true, updateStatus tries to detect that and tracks
|
||||
* the second download when the first one is finished.
|
||||
* By passing false to `follow`, `Download` will only track the first download.
|
||||
*
|
||||
* `getFoo` methods are based on the last statusUpdate.
|
||||
*
|
||||
* @param follow: Do we have to follow following downloads.
|
||||
*/
|
||||
void updateStatus(bool follow);
|
||||
|
||||
/**
|
||||
* Pause the download (and call updateStatus)
|
||||
*/
|
||||
void pauseDownload();
|
||||
|
||||
/**
|
||||
* Resume the download (and call updateStatus)
|
||||
*/
|
||||
void resumeDownload();
|
||||
|
||||
/**
|
||||
* Cancel the download.
|
||||
*
|
||||
* A canceled downlod cannot be resume and updateStatus does nothing.
|
||||
* However, you can still get information based on the last known information.
|
||||
*/
|
||||
void cancelDownload();
|
||||
|
||||
/*
|
||||
* Get the status of the download.
|
||||
*/
|
||||
StatusResult getStatus() const { return m_status; }
|
||||
|
||||
/*
|
||||
* Get the id of the download.
|
||||
*/
|
||||
const std::string& getDid() const { return m_did; }
|
||||
|
||||
/*
|
||||
* Get the id of the "second" download.
|
||||
*
|
||||
* Set only if the "first" download is a metalink and is complete.
|
||||
*/
|
||||
const std::string& getFollowedBy() const { return m_followedBy; }
|
||||
|
||||
/*
|
||||
* Get the total length of the download.
|
||||
*/
|
||||
uint64_t getTotalLength() const { return m_totalLength; }
|
||||
|
||||
/*
|
||||
* Get the completed length of the download.
|
||||
*/
|
||||
uint64_t getCompletedLength() const { return m_completedLength; }
|
||||
|
||||
/*
|
||||
* Get the download speed of the download.
|
||||
*/
|
||||
uint64_t getDownloadSpeed() const { return m_downloadSpeed; }
|
||||
|
||||
/*
|
||||
* Get the verified length of the download.
|
||||
*/
|
||||
uint64_t getVerifiedLength() const { return m_verifiedLength; }
|
||||
|
||||
/*
|
||||
* Get the path (local file) of the download.
|
||||
*/
|
||||
const std::string& getPath() const { return m_path; }
|
||||
|
||||
/*
|
||||
* Get the download uris of the download.
|
||||
*/
|
||||
const std::vector<std::string>& getUris() const { return m_uris; }
|
||||
void updateStatus(bool follow=false);
|
||||
StatusResult getStatus() { return m_status; }
|
||||
std::string getDid() { return m_did; }
|
||||
std::string getFollowedBy() { return m_followedBy; }
|
||||
uint64_t getTotalLength() { return m_totalLength; }
|
||||
uint64_t getCompletedLength() { return m_completedLength; }
|
||||
uint64_t getDownloadSpeed() { return m_downloadSpeed; }
|
||||
uint64_t getVerifiedLength() { return m_verifiedLength; }
|
||||
std::string getPath() { return m_path; }
|
||||
std::vector<std::string>& getUris() { return m_uris; }
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Aria2> mp_aria;
|
||||
@@ -162,69 +80,23 @@ class Download {
|
||||
/**
|
||||
* A tool to download things.
|
||||
*
|
||||
* A Downloader manages `Download` using aria2 in the background.
|
||||
* `Downloader` is threadsafe.
|
||||
* However, the returned `Download`s are NOT threadsafe.
|
||||
*/
|
||||
class Downloader
|
||||
{
|
||||
public: // types
|
||||
typedef std::vector<std::pair<std::string, std::string>> Options;
|
||||
|
||||
public: // functions
|
||||
/*
|
||||
* Create a new Downloader object.
|
||||
*
|
||||
* @param sessionFileDir: The directory where aria2 will store its session file.
|
||||
*/
|
||||
explicit Downloader(std::string sessionFileDir);
|
||||
public:
|
||||
Downloader();
|
||||
virtual ~Downloader();
|
||||
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Start a new download.
|
||||
*
|
||||
* This method is thread safe and returns a pointer to a newly created
|
||||
* `Download` or an existing one with a matching URI. In the latter case
|
||||
* the options parameter is ignored, which can lead to surprising results.
|
||||
* For example, if the old and new download requests (sharing the same URI)
|
||||
* have different values for the download directory or output file name
|
||||
* options, after the download is reported to be complete the downloaded file
|
||||
* will be present only at the location specified for the first request.
|
||||
*
|
||||
* User should call `update` on the returned `Download` to have an accurate status.
|
||||
*
|
||||
* @param uri: The uri of the thing to download.
|
||||
* @param downloadDir: The download directory where the thing should be stored (takes precedence over any "dir" in `options`).
|
||||
* @param options: A series of pair <option_name, option_value> to pass to aria.
|
||||
* @return: The newly created Download.
|
||||
*/
|
||||
std::shared_ptr<Download> startDownload(const std::string& uri, const std::string& downloadDir, Options options = {});
|
||||
Download* startDownload(const std::string& uri);
|
||||
Download* getDownload(const std::string& did);
|
||||
|
||||
/**
|
||||
* Get a download corrsponding to a download id (did)
|
||||
* User should call `update` on the returned `Download` to have an accurate status.
|
||||
*
|
||||
* @param did: The download id to search for.
|
||||
* @return: The Download corresponding to did.
|
||||
* @throw: Throw std::out_of_range if did is not found.
|
||||
*/
|
||||
std::shared_ptr<Download> getDownload(const std::string& did);
|
||||
size_t getNbDownload() { return m_knownDownloads.size(); }
|
||||
std::vector<std::string> getDownloadIds();
|
||||
|
||||
/**
|
||||
* Get the number of downloads currently managed.
|
||||
*/
|
||||
size_t getNbDownload() const;
|
||||
|
||||
/**
|
||||
* Get the ids of the managed downloads.
|
||||
*/
|
||||
std::vector<std::string> getDownloadIds() const;
|
||||
|
||||
private: // data
|
||||
mutable std::mutex m_lock;
|
||||
std::map<std::string, std::shared_ptr<Download>> m_knownDownloads;
|
||||
private:
|
||||
std::map<std::string, std::unique_ptr<Download>> m_knownDownloads;
|
||||
std::shared_ptr<Aria2> mp_aria;
|
||||
};
|
||||
}
|
||||
|
||||
191
include/entry.h
Normal file
191
include/entry.h
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2018 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_ENTRY_H
|
||||
#define KIWIX_ENTRY_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <zim/article.h>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include "common.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
|
||||
class NoEntry : public std::exception {};
|
||||
|
||||
/**
|
||||
* A entry represent an.. entry in a zim file.
|
||||
*/
|
||||
class Entry
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* Construct an invalid entry.
|
||||
*/
|
||||
Entry() = default;
|
||||
|
||||
/**
|
||||
* Construct an entry making reference to an zim article.
|
||||
*
|
||||
* @param article a zim::Article object
|
||||
*/
|
||||
Entry(zim::Article article);
|
||||
virtual ~Entry() = default;
|
||||
|
||||
/**
|
||||
* Get the path of the entry.
|
||||
*
|
||||
* The path is the "key" of an entry.
|
||||
*
|
||||
* @return the path of the entry.
|
||||
*/
|
||||
std::string getPath() const;
|
||||
|
||||
/**
|
||||
* Get the title of the entry.
|
||||
*
|
||||
* @return the title of the entry.
|
||||
*/
|
||||
std::string getTitle() const;
|
||||
|
||||
/**
|
||||
* Get the content of the entry.
|
||||
*
|
||||
* The string is a copy of the content.
|
||||
* If you don't want to do a copy, use get_blob.
|
||||
*
|
||||
* @return the content of the entry.
|
||||
*/
|
||||
std::string getContent() const;
|
||||
|
||||
/**
|
||||
* Get the blob of the entry.
|
||||
*
|
||||
* A blob make reference to the content without copying it.
|
||||
*
|
||||
* @param offset The starting offset of the blob.
|
||||
* @return the blob of the entry.
|
||||
*/
|
||||
zim::Blob getBlob(offset_type offset = 0) const;
|
||||
|
||||
/**
|
||||
* Get the blob of the entry.
|
||||
*
|
||||
* A blob make reference to the content without copying it.
|
||||
*
|
||||
* @param offset The starting offset of the blob.
|
||||
* @param size The size of the blob.
|
||||
* @return the blob of the entry.
|
||||
*/
|
||||
zim::Blob getBlob(offset_type offset, size_type size) const;
|
||||
|
||||
/**
|
||||
* Get the info for direct access to the content of the entry.
|
||||
*
|
||||
* Some entry (ie binary ones) have their content plain stored
|
||||
* in the zim file. Knowing the offset where the content is stored
|
||||
* an user can directly read the content in the zim file bypassing the
|
||||
* kiwix-lib/libzim.
|
||||
*
|
||||
* @return A pair specifying where to read the content.
|
||||
* The string is the real file to read (may be different that .zim
|
||||
* file if zim is cut).
|
||||
* The offset is the offset to read in the file.
|
||||
* Return <"",0> if is not possible to read directly.
|
||||
*/
|
||||
std::pair<std::string, offset_type> getDirectAccessInfo() const;
|
||||
|
||||
/**
|
||||
* Get the size of the entry.
|
||||
*
|
||||
* @return the size of the entry.
|
||||
*/
|
||||
size_type getSize() const;
|
||||
|
||||
/**
|
||||
* Get the mime_type of the entry.
|
||||
*
|
||||
* @return the mime_type of the entry.
|
||||
*/
|
||||
std::string getMimetype() const;
|
||||
|
||||
|
||||
/**
|
||||
* Get if the entry is a redirect entry.
|
||||
*
|
||||
* @return True if the entry is a redirect.
|
||||
*/
|
||||
bool isRedirect() const;
|
||||
|
||||
/**
|
||||
* Get if the entry is a link target entry.
|
||||
*
|
||||
* @return True if the entry is a link target.
|
||||
*/
|
||||
bool isLinkTarget() const;
|
||||
|
||||
/**
|
||||
* Get if the entry is a deleted entry.
|
||||
*
|
||||
* @return True if the entry is a deleted entry.
|
||||
*/
|
||||
bool isDeleted() const;
|
||||
|
||||
/**
|
||||
* Get the entry pointed by this entry.
|
||||
*
|
||||
* @return the entry pointed.
|
||||
* @throw NoEntry if the entry is not a redirected entry.
|
||||
*/
|
||||
Entry getRedirectEntry() const;
|
||||
|
||||
/**
|
||||
* Get the final entry pointed by this entry.
|
||||
*
|
||||
* Follow the redirection until a "not redirecting" entry is found.
|
||||
* If the entry is not a redirected entry, return the entry itself.
|
||||
*
|
||||
* @return the final entry.
|
||||
*/
|
||||
Entry getFinalEntry() const;
|
||||
|
||||
/**
|
||||
* Convert the entry to a boolean value.
|
||||
*
|
||||
* @return True if the entry is valid.
|
||||
*/
|
||||
explicit operator bool() const { return good(); }
|
||||
|
||||
private:
|
||||
zim::Article article;
|
||||
mutable zim::Article final_article;
|
||||
|
||||
bool good() const { return article.good(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // KIWIX_ENTRY_H
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 Veloman Yunkan <veloman.yunkan@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_I18N
|
||||
#define KIWIX_I18N
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
std::string getTranslatedString(const std::string& lang, const std::string& key);
|
||||
|
||||
namespace i18n
|
||||
{
|
||||
|
||||
typedef std::map<std::string, std::string> Parameters;
|
||||
|
||||
std::string expandParameterizedString(const std::string& lang,
|
||||
const std::string& key,
|
||||
const Parameters& params);
|
||||
|
||||
class GetTranslatedString
|
||||
{
|
||||
public:
|
||||
explicit GetTranslatedString(const std::string& lang) : m_lang(lang) {}
|
||||
|
||||
std::string operator()(const std::string& key) const
|
||||
{
|
||||
return getTranslatedString(m_lang, key);
|
||||
}
|
||||
|
||||
std::string operator()(const std::string& key, const Parameters& params) const
|
||||
{
|
||||
return expandParameterizedString(m_lang, key, params);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string m_lang;
|
||||
};
|
||||
|
||||
} // namespace i18n
|
||||
|
||||
class ParameterizedMessage
|
||||
{
|
||||
public: // types
|
||||
typedef i18n::Parameters Parameters;
|
||||
|
||||
public: // functions
|
||||
ParameterizedMessage(const std::string& msgId, const Parameters& params)
|
||||
: msgId(msgId)
|
||||
, params(params)
|
||||
{}
|
||||
|
||||
std::string getText(const std::string& lang) const;
|
||||
|
||||
const std::string& getMsgId() const { return msgId; }
|
||||
const Parameters& getParams() const { return params; }
|
||||
|
||||
private: // data
|
||||
const std::string msgId;
|
||||
const Parameters params;
|
||||
};
|
||||
|
||||
inline ParameterizedMessage nonParameterizedMessage(const std::string& msgId)
|
||||
{
|
||||
const ParameterizedMessage::Parameters noParams;
|
||||
return ParameterizedMessage(msgId, noParams);
|
||||
}
|
||||
|
||||
std::string translateBookCategory(const std::string& lang, const std::string& category);
|
||||
|
||||
} // namespace kiwix
|
||||
|
||||
#endif // KIWIX_I18N
|
||||
@@ -22,4 +22,4 @@
|
||||
|
||||
#include "library.h"
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef KIWIXLIB_KIWIX_SERVE_H_
|
||||
#define KIWIXLIB_KIWIX_SERVE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class Subprocess;
|
||||
namespace kiwix {
|
||||
|
||||
class KiwixServe
|
||||
{
|
||||
public:
|
||||
KiwixServe(const std::string& libraryPath, int port = 8181);
|
||||
~KiwixServe();
|
||||
|
||||
void run();
|
||||
void shutDown();
|
||||
bool isRunning();
|
||||
int getPort() { return m_port; }
|
||||
int setPort(int port);
|
||||
|
||||
private:
|
||||
std::unique_ptr<Subprocess> mp_kiwixServe;
|
||||
int m_port;
|
||||
std::string m_libraryPath;
|
||||
};
|
||||
|
||||
}; //end namespace kiwix
|
||||
|
||||
#endif // KIWIXLIB_KIWIX_SERVE_H_
|
||||
@@ -23,26 +23,14 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <zim/archive.h>
|
||||
#include <zim/search.h>
|
||||
|
||||
#include "book.h"
|
||||
#include "bookmark.h"
|
||||
#include "common.h"
|
||||
|
||||
#define KIWIX_LIBRARY_VERSION "20110515"
|
||||
|
||||
namespace Xapian {
|
||||
class WritableDatabase;
|
||||
};
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
class Book;
|
||||
class OPDSDumper;
|
||||
class Library;
|
||||
|
||||
enum supportedListSortBy { UNSORTED, TITLE, SIZE, DATE, CREATOR, PUBLISHER };
|
||||
enum supportedListMode {
|
||||
@@ -54,198 +42,17 @@ enum supportedListMode {
|
||||
VALID = 1 << 4,
|
||||
NOVALID = 1 << 5
|
||||
};
|
||||
|
||||
enum MigrationMode {
|
||||
/** When migrating bookmarks, do not allow to migrate to an older book than the currently pointed one
|
||||
* (or date stored in the bookmark if book is invalid)
|
||||
*
|
||||
* If no newer books are found, no upgrade is made.
|
||||
*/
|
||||
UPGRADE_ONLY = 0,
|
||||
|
||||
/** Try hard to do a migration. This mostly does:
|
||||
* - Try to find a newer book.
|
||||
* - If book is invalid: find a best book, potentially older.
|
||||
* Older book will never be returned if current book is a valid one.
|
||||
*/
|
||||
ALLOW_DOWNGRADE = 1,
|
||||
};
|
||||
|
||||
class Filter {
|
||||
public: // types
|
||||
using Tags = std::vector<std::string>;
|
||||
|
||||
private: // data
|
||||
uint64_t activeFilters;
|
||||
Tags _acceptTags;
|
||||
Tags _rejectTags;
|
||||
std::string _category;
|
||||
std::string _lang;
|
||||
std::string _publisher;
|
||||
std::string _creator;
|
||||
size_t _maxSize;
|
||||
std::string _query;
|
||||
bool _queryIsPartial;
|
||||
std::string _name;
|
||||
std::string _flavour;
|
||||
|
||||
public: // functions
|
||||
Filter();
|
||||
~Filter() = default;
|
||||
|
||||
/**
|
||||
* Set the filter to check local.
|
||||
*
|
||||
* A local book is a book with a path.
|
||||
* If accept is true, only local book are accepted.
|
||||
* If accept is false, only non local book are accepted.
|
||||
*/
|
||||
Filter& local(bool accept);
|
||||
|
||||
/**
|
||||
* Set the filter to check remote.
|
||||
*
|
||||
* A remote book is a book with a url.
|
||||
* If accept is true, only remote book are accepted.
|
||||
* If accept is false, only non remote book are accepted.
|
||||
*/
|
||||
Filter& remote(bool accept);
|
||||
|
||||
/**
|
||||
* Set the filter to check validity.
|
||||
*
|
||||
* A valid book is a book with a path pointing to a existing zim file.
|
||||
* If accept is true, only valid book are accepted.
|
||||
* If accept is false, only non valid book are accepted.
|
||||
*/
|
||||
Filter& valid(bool accept);
|
||||
|
||||
/**
|
||||
* Set the filter to only accept book with corresponding tag.
|
||||
*/
|
||||
Filter& acceptTags(const Tags& tags);
|
||||
Filter& rejectTags(const Tags& tags);
|
||||
|
||||
/**
|
||||
* Set the filter to only accept books in the specified category.
|
||||
*
|
||||
* Multiple categories can be specified as a comma-separated list (in
|
||||
* which case a book in any of those categories will match).
|
||||
*/
|
||||
Filter& category(std::string category);
|
||||
|
||||
/**
|
||||
* Set the filter to only accept books in the specified language.
|
||||
*
|
||||
* Multiple languages can be specified as a comma-separated list (in
|
||||
* which case a book in any of those languages will match).
|
||||
*/
|
||||
Filter& lang(std::string lang);
|
||||
|
||||
Filter& publisher(std::string publisher);
|
||||
Filter& creator(std::string creator);
|
||||
Filter& maxSize(size_t size);
|
||||
Filter& query(std::string query, bool partial=true);
|
||||
Filter& name(std::string name);
|
||||
Filter& flavour(std::string flavour);
|
||||
Filter& clearLang();
|
||||
Filter& clearCategory();
|
||||
|
||||
bool hasQuery() const;
|
||||
const std::string& getQuery() const { return _query; }
|
||||
bool queryIsPartial() const { return _queryIsPartial; }
|
||||
|
||||
bool hasName() const;
|
||||
const std::string& getName() const { return _name; }
|
||||
|
||||
bool hasCategory() const;
|
||||
const std::string& getCategory() const { return _category; }
|
||||
|
||||
bool hasLang() const;
|
||||
const std::string& getLang() const { return _lang; }
|
||||
|
||||
bool hasPublisher() const;
|
||||
const std::string& getPublisher() const { return _publisher; }
|
||||
|
||||
bool hasCreator() const;
|
||||
const std::string& getCreator() const { return _creator; }
|
||||
|
||||
bool hasFlavour() const;
|
||||
const std::string& getFlavour() const { return _flavour; }
|
||||
|
||||
const Tags& getAcceptTags() const { return _acceptTags; }
|
||||
const Tags& getRejectTags() const { return _rejectTags; }
|
||||
|
||||
private: // functions
|
||||
friend class Library;
|
||||
|
||||
bool accept(const Book& book) const;
|
||||
};
|
||||
|
||||
|
||||
class ZimSearcher : public zim::Searcher
|
||||
{
|
||||
public:
|
||||
explicit ZimSearcher(zim::Searcher&& searcher)
|
||||
: zim::Searcher(searcher)
|
||||
{}
|
||||
|
||||
std::unique_lock<std::mutex> getLock() {
|
||||
return std::unique_lock<std::mutex>(m_mutex);
|
||||
}
|
||||
virtual ~ZimSearcher() = default;
|
||||
private:
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
template<typename, typename>
|
||||
class ConcurrentCache;
|
||||
|
||||
template<typename, typename>
|
||||
class MultiKeyCache;
|
||||
|
||||
using LibraryPtr = std::shared_ptr<Library>;
|
||||
using ConstLibraryPtr = std::shared_ptr<const Library>;
|
||||
|
||||
|
||||
// Some compiler we use don't have [[nodiscard]] attribute.
|
||||
// We don't want to declare `create` with it in this case.
|
||||
#define LIBKIWIX_NODISCARD
|
||||
#if defined __has_cpp_attribute
|
||||
#if __has_cpp_attribute (nodiscard)
|
||||
#undef LIBKIWIX_NODISCARD
|
||||
#define LIBKIWIX_NODISCARD [[nodiscard]]
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A Library store several books.
|
||||
*/
|
||||
class Library: public std::enable_shared_from_this<Library>
|
||||
class Library
|
||||
{
|
||||
std::map<std::string, kiwix::Book> books;
|
||||
public:
|
||||
typedef uint64_t Revision;
|
||||
typedef std::vector<std::string> BookIdCollection;
|
||||
typedef std::map<std::string, int> AttributeCounts;
|
||||
typedef std::set<std::string> BookIdSet;
|
||||
|
||||
private:
|
||||
Library();
|
||||
|
||||
public:
|
||||
LIBKIWIX_NODISCARD static LibraryPtr create() {
|
||||
return LibraryPtr(new Library());
|
||||
}
|
||||
~Library();
|
||||
|
||||
/**
|
||||
* Library is not a copiable object. However it can be moved.
|
||||
*/
|
||||
Library(const Library& ) = delete;
|
||||
Library(Library&& ) = delete;
|
||||
void operator=(const Library& ) = delete;
|
||||
Library& operator=(Library&& ) = delete;
|
||||
|
||||
std::string version;
|
||||
/**
|
||||
* Add a book to the library.
|
||||
*
|
||||
@@ -258,99 +65,7 @@ class Library: public std::enable_shared_from_this<Library>
|
||||
*/
|
||||
bool addBook(const Book& book);
|
||||
|
||||
/**
|
||||
* A self-explanatory alias for addBook()
|
||||
*/
|
||||
bool addOrUpdateBook(const Book& book) { return addBook(book); }
|
||||
|
||||
/**
|
||||
* Add a bookmark to the library.
|
||||
*
|
||||
* @param bookmark the book to add.
|
||||
*/
|
||||
void addBookmark(const Bookmark& bookmark);
|
||||
|
||||
/**
|
||||
* Remove a bookmark
|
||||
*
|
||||
* @param zimId The zimId of the bookmark.
|
||||
* @param url The url of the bookmark.
|
||||
* @return True if the bookmark has been removed.
|
||||
*/
|
||||
bool removeBookmark(const std::string& zimId, const std::string& url);
|
||||
|
||||
/**
|
||||
* Migrate all invalid bookmarks.
|
||||
*
|
||||
* All invalid bookmarks (ie pointing to unknown books, no check is made on bookmark pointing to
|
||||
* invalid articles of valid book) will be migrated (if possible) to a better book.
|
||||
* "Better book", will be determined using method `getBestTargetBookId`.
|
||||
*
|
||||
* @return A tuple<int, int>: <The number of bookmarks updated>, <Number of invalid bookmarks before migration was performed>.
|
||||
*/
|
||||
std::tuple<int, int> migrateBookmarks(MigrationMode migrationMode = ALLOW_DOWNGRADE);
|
||||
|
||||
/**
|
||||
* Migrate all bookmarks associated to a specific book.
|
||||
*
|
||||
* All bookmarks associated to `sourceBookId` book will be migrated to a better book.
|
||||
* "Better book", will be determined using method `getBestTargetBookId`.
|
||||
*
|
||||
* @param sourceBookId the source bookId of the bookmarks to migrate.
|
||||
* @param migrationMode how we will find the best book.
|
||||
* @return The number of bookmarks updated.
|
||||
*/
|
||||
int migrateBookmarks(const std::string& sourceBookId, MigrationMode migrationMode = UPGRADE_ONLY);
|
||||
|
||||
/**
|
||||
* Migrate bookmarks
|
||||
*
|
||||
* Migrate all bookmarks pointing to `source` to `destination`.
|
||||
*
|
||||
* @param sourceBookId the source bookId of the bookmarks to migrate.
|
||||
* @param targetBookId the destination bookId to migrate the bookmarks to.
|
||||
* @return The number of bookmarks updated.
|
||||
*/
|
||||
int migrateBookmarks(const std::string& sourceBookId, const std::string& targetBookId);
|
||||
|
||||
/**
|
||||
* Get the best available bookId for a bookmark.
|
||||
*
|
||||
* Given a bookmark, return the best available bookId.
|
||||
* "best available bookId" is determined using heuristitcs based on book name, flavour and date.
|
||||
*
|
||||
* @param bookmark The bookmark to search the bookId for.
|
||||
* @param migrationMode The migration mode to use.
|
||||
* @return A bookId. Potentially empty string if no suitable book found.
|
||||
*/
|
||||
std::string getBestTargetBookId(const Bookmark& bookmark, MigrationMode migrationMode) const;
|
||||
|
||||
/**
|
||||
* Get the best bookId for a combination of book's name, flavour and date.
|
||||
*
|
||||
* Given a bookName (mandatory), try to find the best book.
|
||||
* If preferedFlavour is given, will try to find a book with the same flavour. If not found, return a book with a different flavour.
|
||||
* If minDate is given, return a book newer than minDate. If not found, return a empty bookId.
|
||||
*
|
||||
* @param bookName The name of the book
|
||||
* @param preferedFlavour The prefered flavour.
|
||||
* @param minDate the minimal book date acceptable. Must be a string in the format "YYYY-MM-DD".
|
||||
* @return A bookId corresponding to the query, or empty string if not found.
|
||||
*/
|
||||
std::string getBestTargetBookId(const std::string& bookName, const std::string& preferedFlavour="", const std::string& minDate="") const;
|
||||
|
||||
// XXX: This is a non-thread-safe operation
|
||||
const Book& getBookById(const std::string& id) const;
|
||||
// XXX: This is a non-thread-safe operation
|
||||
const Book& getBookByPath(const std::string& path) const;
|
||||
|
||||
Book getBookByIdThreadSafe(const std::string& id) const;
|
||||
|
||||
std::shared_ptr<zim::Archive> getArchiveById(const std::string& id);
|
||||
std::shared_ptr<ZimSearcher> getSearcherById(const std::string& id) {
|
||||
return getSearcherByIds(BookIdSet{id});
|
||||
}
|
||||
std::shared_ptr<ZimSearcher> getSearcherByIds(const BookIdSet& ids);
|
||||
Book& getBookById(const std::string& id);
|
||||
|
||||
/**
|
||||
* Remove a book from the library.
|
||||
@@ -364,17 +79,9 @@ class Library: public std::enable_shared_from_this<Library>
|
||||
* Write the library to a file.
|
||||
*
|
||||
* @param path the path of the file to write to.
|
||||
* @return True if the library has been correctly saved.
|
||||
* @return True if the library has been correctly save.
|
||||
*/
|
||||
bool writeToFile(const std::string& path) const;
|
||||
|
||||
/**
|
||||
* Write the library bookmarks to a file.
|
||||
*
|
||||
* @param path the path of the file to write to.
|
||||
* @return True if the library has been correctly saved.
|
||||
*/
|
||||
bool writeBookmarksToFile(const std::string& path) const;
|
||||
bool writeToFile(const std::string& path);
|
||||
|
||||
/**
|
||||
* Get the number of book in the library.
|
||||
@@ -383,129 +90,80 @@ class Library: public std::enable_shared_from_this<Library>
|
||||
* @param remoteBooks If we must count remote books (books with an url)
|
||||
* @return The number of books.
|
||||
*/
|
||||
unsigned int getBookCount(const bool localBooks, const bool remoteBooks) const;
|
||||
unsigned int getBookCount(const bool localBooks, const bool remoteBooks);
|
||||
|
||||
/**
|
||||
* Get all languagues of the books in the library.
|
||||
* Get all langagues of the books in the library.
|
||||
*
|
||||
* @return A list of languages.
|
||||
*/
|
||||
std::vector<std::string> getBooksLanguages() const;
|
||||
|
||||
/**
|
||||
* Get all languagues of the books in the library with counts.
|
||||
*
|
||||
* @return A list of languages with the count of books in each language.
|
||||
*/
|
||||
AttributeCounts getBooksLanguagesWithCounts() const;
|
||||
|
||||
/**
|
||||
* Get all categories of the books in the library.
|
||||
*
|
||||
* @return A list of categories.
|
||||
*/
|
||||
std::vector<std::string> getBooksCategories() const;
|
||||
std::vector<std::string> getBooksLanguages();
|
||||
|
||||
/**
|
||||
* Get all book creators of the books in the library.
|
||||
*
|
||||
* @return A list of book creators.
|
||||
*/
|
||||
std::vector<std::string> getBooksCreators() const;
|
||||
std::vector<std::string> getBooksCreators();
|
||||
|
||||
/**
|
||||
* Get all book publishers of the books in the library.
|
||||
*
|
||||
* @return A list of book publishers.
|
||||
*/
|
||||
std::vector<std::string> getBooksPublishers() const;
|
||||
|
||||
/**
|
||||
* Get all bookmarks.
|
||||
*
|
||||
* @return A list of bookmarks
|
||||
*/
|
||||
const std::vector<kiwix::Bookmark> getBookmarks(bool onlyValidBookmarks = true) const;
|
||||
std::vector<std::string> getBooksPublishers();
|
||||
|
||||
/**
|
||||
* Get all book ids of the books in the library.
|
||||
*
|
||||
* @return A list of book ids.
|
||||
*/
|
||||
BookIdCollection getBooksIds() const;
|
||||
std::vector<std::string> getBooksIds();
|
||||
|
||||
/**
|
||||
* Filter the library and return the id of the keep elements.
|
||||
* Filter the library and generate a new one with the keep elements.
|
||||
*
|
||||
* @param filter The filter to use.
|
||||
* @return The list of bookIds corresponding to the filter.
|
||||
* This is equivalent to `listBookIds(ALL, UNSORTED, search)`.
|
||||
*
|
||||
* @param search List only books with search in the title or description.
|
||||
* @return The list of bookIds corresponding to the query.
|
||||
*/
|
||||
BookIdCollection filter(const Filter& filter) const;
|
||||
std::vector<std::string> filter(const std::string& search);
|
||||
|
||||
|
||||
/**
|
||||
* Sort (in place) bookIds using the given comparator.
|
||||
* List books in the library.
|
||||
*
|
||||
* @param bookIds the list of book Ids to sort
|
||||
* @param comparator how to sort the books
|
||||
* @return The sorted list of books
|
||||
* @param mode The mode of listing :
|
||||
* - LOCAL : list only local books (with a path).
|
||||
* - REMOTE : list only remote books (with an url).
|
||||
* - VALID : list only valid books (without a path or with a
|
||||
* path pointing to a valid zim file).
|
||||
* - NOLOCAL : list only books without valid path.
|
||||
* - NOREMOTE : list only books without url.
|
||||
* - NOVALID : list only books not valid.
|
||||
* - ALL : Do not do any filter (LOCAL or REMOTE)
|
||||
* - Flags can be combined.
|
||||
* @param sortBy Attribute to sort by the book list.
|
||||
* @param search List only books with search in the title, description.
|
||||
* @param language List only books in this language.
|
||||
* @param creator List only books of this creator.
|
||||
* @param publisher List only books of this publisher.
|
||||
* @param maxSize Do not list book bigger than maxSize.
|
||||
* Set to 0 to cancel this filter.
|
||||
* @return The list of bookIds corresponding to the query.
|
||||
*/
|
||||
void sort(BookIdCollection& bookIds, supportedListSortBy sortBy, bool ascending) const;
|
||||
|
||||
/**
|
||||
* Return the current revision of the library.
|
||||
*
|
||||
* The revision of the library is updated (incremented by one) by
|
||||
* the addBook() and removeBookById() operations.
|
||||
*
|
||||
* @return Current revision of the library.
|
||||
*/
|
||||
Revision getRevision() const;
|
||||
|
||||
/**
|
||||
* Remove books that have not been updated since the specified revision.
|
||||
*
|
||||
* @param rev the library revision to use
|
||||
* @return Count of books that were removed by this operation.
|
||||
*/
|
||||
uint32_t removeBooksNotUpdatedSince(Revision rev);
|
||||
std::vector<std::string> listBooksIds(
|
||||
int supportedListMode = ALL,
|
||||
supportedListSortBy sortBy = UNSORTED,
|
||||
const std::string& search = "",
|
||||
const std::string& language = "",
|
||||
const std::string& creator = "",
|
||||
const std::string& publisher = "",
|
||||
size_t maxSize = 0);
|
||||
|
||||
friend class OPDSDumper;
|
||||
friend class libXMLDumper;
|
||||
|
||||
private: // types
|
||||
typedef const std::string& (Book::*BookStrPropMemFn)() const;
|
||||
struct Entry : Book
|
||||
{
|
||||
Library::Revision lastUpdatedRevision = 0;
|
||||
};
|
||||
|
||||
private: // functions
|
||||
AttributeCounts getBookAttributeCounts(BookStrPropMemFn p) const;
|
||||
std::vector<std::string> getBookPropValueSet(BookStrPropMemFn p) const;
|
||||
BookIdCollection filterViaBookDB(const Filter& filter) const;
|
||||
std::string getBestFromBookCollection(BookIdCollection books, const Bookmark& bookmark, MigrationMode migrationMode) const;
|
||||
unsigned int getBookCount_not_protected(const bool localBooks, const bool remoteBooks) const;
|
||||
void updateBookDB(const Book& book);
|
||||
void dropCache(const std::string& bookId);
|
||||
|
||||
private: //data
|
||||
mutable std::recursive_mutex m_mutex;
|
||||
Library::Revision m_revision;
|
||||
std::map<std::string, Entry> m_books;
|
||||
using ArchiveCache = ConcurrentCache<std::string, std::shared_ptr<zim::Archive>>;
|
||||
std::unique_ptr<ArchiveCache> mp_archiveCache;
|
||||
using SearcherCache = MultiKeyCache<std::string, std::shared_ptr<ZimSearcher>>;
|
||||
std::unique_ptr<SearcherCache> mp_searcherCache;
|
||||
std::vector<kiwix::Bookmark> m_bookmarks;
|
||||
std::unique_ptr<Xapian::WritableDatabase> m_bookDB;
|
||||
};
|
||||
|
||||
// We don't need it anymore and we don't want to polute any other potential usage
|
||||
// of `LIBKIWIX_NODISCARD` token.
|
||||
#undef LIBKIWIX_NODISCARD
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
|
||||
#include "book.h"
|
||||
#include "library.h"
|
||||
#include "reader.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace pugi {
|
||||
class xml_document;
|
||||
@@ -34,60 +34,60 @@ class xml_document;
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
class LibraryManipulator
|
||||
{
|
||||
public: // functions
|
||||
explicit LibraryManipulator(LibraryPtr library);
|
||||
virtual ~LibraryManipulator();
|
||||
class LibraryManipulator {
|
||||
public:
|
||||
virtual ~LibraryManipulator() {}
|
||||
virtual bool addBookToLibrary(Book book) = 0;
|
||||
};
|
||||
|
||||
LibraryPtr getLibrary() const { return library; }
|
||||
|
||||
bool addBookToLibrary(const Book& book);
|
||||
void addBookmarkToLibrary(const Bookmark& bookmark);
|
||||
uint32_t removeBooksNotUpdatedSince(Library::Revision rev);
|
||||
|
||||
protected: // overrides
|
||||
virtual void bookWasAddedToLibrary(const Book& book);
|
||||
virtual void bookmarkWasAddedToLibrary(const Bookmark& bookmark);
|
||||
virtual void booksWereRemovedFromLibrary();
|
||||
|
||||
private: // data
|
||||
LibraryPtr library;
|
||||
class DefaultLibraryManipulator : public LibraryManipulator {
|
||||
public:
|
||||
DefaultLibraryManipulator(Library* library) :
|
||||
library(library) {}
|
||||
virtual ~DefaultLibraryManipulator() {}
|
||||
bool addBookToLibrary(Book book) {
|
||||
return library->addBook(book);
|
||||
}
|
||||
private:
|
||||
kiwix::Library* library;
|
||||
};
|
||||
|
||||
/**
|
||||
* A tool to manage a `Library`.
|
||||
*
|
||||
* A `Manager` handle a internal `Library`.
|
||||
* This `Library` can be retrived with `cloneLibrary` method.
|
||||
*/
|
||||
class Manager
|
||||
{
|
||||
public: // types
|
||||
typedef std::vector<std::string> Paths;
|
||||
|
||||
public: // functions
|
||||
explicit Manager(LibraryManipulator manipulator);
|
||||
explicit Manager(LibraryPtr library);
|
||||
public:
|
||||
Manager(LibraryManipulator* manipulator);
|
||||
Manager(Library* library);
|
||||
~Manager();
|
||||
|
||||
/**
|
||||
* Read a `library.xml` and add book in the file to the library.
|
||||
*
|
||||
* @param path The (utf8) path to the `library.xml`.
|
||||
* @param path The path to the `library.xml`.
|
||||
* @param readOnly Set if the libray path could be overwritten latter with
|
||||
* updated content.
|
||||
* @param trustLibrary use book metadata coming from XML.
|
||||
* @return True if file has been properly parsed.
|
||||
*/
|
||||
bool readFile(const std::string& path, bool readOnly = true, bool trustLibrary = true);
|
||||
bool readFile(const std::string& path, const bool readOnly = true);
|
||||
|
||||
/**
|
||||
* Sync the contents of the library with one or more `library.xml` files.
|
||||
* Read a `library.xml` and add book in the file to the library.
|
||||
*
|
||||
* The metadata of the library files is trusted unconditionally.
|
||||
* Any books not present in the input library.xml files are removed
|
||||
* from the library.
|
||||
*
|
||||
* @param paths The (utf8) paths to the `library.xml` files.
|
||||
* @param nativePath The path of the `library.xml`
|
||||
* @param UTF8Path The utf8 version (?) of the path. Also the path where the
|
||||
* library will be writen i readOnly is False.
|
||||
* @param readOnly Set if the libray path could be overwritten latter with
|
||||
* updated content.
|
||||
* @return True if file has been properly parsed.
|
||||
*/
|
||||
void reload(const Paths& paths);
|
||||
bool readFile(const std::string& nativePath,
|
||||
const std::string& UTF8Path,
|
||||
const bool readOnly = true);
|
||||
|
||||
/**
|
||||
* Load a library content store in the string.
|
||||
@@ -100,8 +100,7 @@ class Manager
|
||||
*/
|
||||
bool readXml(const std::string& xml,
|
||||
const bool readOnly = true,
|
||||
const std::string& libraryPath = "",
|
||||
bool trustLibrary = true);
|
||||
const std::string& libraryPath = "");
|
||||
|
||||
/**
|
||||
* Load a library content stored in a OPDS stream.
|
||||
@@ -114,15 +113,6 @@ class Manager
|
||||
*/
|
||||
bool readOpds(const std::string& content, const std::string& urlHost);
|
||||
|
||||
|
||||
/**
|
||||
* Load a bookmark file.
|
||||
*
|
||||
* @param path The path of the file to read.
|
||||
* @return True if the content has been properly parsed.
|
||||
*/
|
||||
bool readBookmarkFile(const std::string& path);
|
||||
|
||||
/**
|
||||
* Add a book to the library.
|
||||
*
|
||||
@@ -156,13 +146,53 @@ class Manager
|
||||
const bool checkMetaData = false);
|
||||
|
||||
/**
|
||||
* Add all books from the directory tree into the library.
|
||||
*
|
||||
* @param path The path of the directory to scan.
|
||||
* @param verboseFlag Verbose logs flag.
|
||||
* Get the book corresponding to an id.
|
||||
*
|
||||
* @param[in] id The id of the book
|
||||
* @param[out] book The book corresponding to the id.
|
||||
* @return True if the book has been found.
|
||||
*/
|
||||
void addBooksFromDirectory(const std::string& path,
|
||||
const bool verboseFlag = false);
|
||||
bool getBookById(const std::string& id, Book& book);
|
||||
|
||||
/**
|
||||
* Update the "last open date" of a book
|
||||
*
|
||||
* @param id the id of the book.
|
||||
* @return True if the book is in the library.
|
||||
*/
|
||||
bool updateBookLastOpenDateById(const std::string& id);
|
||||
|
||||
/**
|
||||
* Remove (set to empty) paths of all books in the library.
|
||||
*/
|
||||
void removeBookPaths();
|
||||
|
||||
/**
|
||||
* List books in the library.
|
||||
*
|
||||
* The books list will be available in public vector member `bookIdList`.
|
||||
*
|
||||
* @param mode The mode of listing :
|
||||
* - LASTOPEN sort by last opened book.
|
||||
* - LOCAL list only local file.
|
||||
* - REMOTE list only remote file.
|
||||
* @param sortBy Attribute to sort by the book list.
|
||||
* @param maxSize Do not list book bigger than maxSize MiB.
|
||||
* Set to 0 to cancel this filter.
|
||||
* @param language List only books in this language.
|
||||
* @param creator List only books of this creator.
|
||||
* @param publisher List only books of this publisher.
|
||||
* @param search List only books with search in the title, description or
|
||||
* language.
|
||||
* @return True
|
||||
*/
|
||||
bool listBooks(const supportedListMode mode,
|
||||
const supportedListSortBy sortBy,
|
||||
const unsigned int maxSize,
|
||||
const std::string& language,
|
||||
const std::string& creator,
|
||||
const std::string& publisher,
|
||||
const std::string& search);
|
||||
|
||||
std::string writableLibraryPath;
|
||||
|
||||
@@ -172,16 +202,18 @@ class Manager
|
||||
uint64_t m_itemsPerPage = 0;
|
||||
|
||||
protected:
|
||||
kiwix::LibraryManipulator manipulator;
|
||||
kiwix::LibraryManipulator* manipulator;
|
||||
bool mustDeleteManipulator;
|
||||
|
||||
bool readBookFromPath(const std::string& path, Book* book);
|
||||
bool parseXmlDom(const pugi::xml_document& doc,
|
||||
bool readOnly,
|
||||
const std::string& libraryPath,
|
||||
bool trustLibrary);
|
||||
const bool readOnly,
|
||||
const std::string& libraryPath);
|
||||
bool parseOpdsDom(const pugi::xml_document& doc,
|
||||
const std::string& urlHost);
|
||||
|
||||
private:
|
||||
void checkAndCleanBookPaths(Book& book, const std::string& libraryPath);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,35 @@
|
||||
headers = [
|
||||
'book.h',
|
||||
'bookmark.h',
|
||||
'common.h',
|
||||
'library.h',
|
||||
'manager.h',
|
||||
'opds_dumper.h',
|
||||
'downloader.h',
|
||||
'search_renderer.h',
|
||||
'server.h',
|
||||
'spelling_correction.h',
|
||||
'kiwixserve.h',
|
||||
'name_mapper.h',
|
||||
'tools.h',
|
||||
'version.h',
|
||||
'i18n.h'
|
||||
'reader.h',
|
||||
'entry.h',
|
||||
'searcher.h'
|
||||
]
|
||||
|
||||
if xapian_dep.found()
|
||||
headers += ['xapianSearcher.h']
|
||||
endif
|
||||
|
||||
install_headers(headers, subdir:'kiwix')
|
||||
|
||||
install_headers(
|
||||
'common/base64.h',
|
||||
'common/networkTools.h',
|
||||
'common/otherTools.h',
|
||||
'common/pathTools.h',
|
||||
'common/regexTools.h',
|
||||
'common/stringTools.h',
|
||||
subdir:'kiwix/common'
|
||||
)
|
||||
|
||||
if has_ctpp2_dep
|
||||
install_headers(
|
||||
'ctpp2/CTPP2VMStringLoader.hpp',
|
||||
subdir:'kiwix/ctpp2'
|
||||
)
|
||||
endif
|
||||
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_NAMEMAPPER_H
|
||||
#define KIWIX_NAMEMAPPER_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
class Library;
|
||||
|
||||
class NameMapper {
|
||||
public:
|
||||
virtual ~NameMapper() = default;
|
||||
virtual std::string getNameForId(const std::string& id) const = 0;
|
||||
virtual std::string getIdForName(const std::string& name) const = 0;
|
||||
};
|
||||
|
||||
|
||||
class IdNameMapper : public NameMapper {
|
||||
public:
|
||||
virtual std::string getNameForId(const std::string& id) const { return id; };
|
||||
virtual std::string getIdForName(const std::string& name) const { return name; };
|
||||
};
|
||||
|
||||
class HumanReadableNameMapper : public NameMapper {
|
||||
private:
|
||||
std::map<std::string, std::string> m_idToName;
|
||||
std::map<std::string, std::string> m_nameToId;
|
||||
|
||||
public:
|
||||
HumanReadableNameMapper(const kiwix::Library& library, bool withAlias);
|
||||
virtual ~HumanReadableNameMapper() = default;
|
||||
virtual std::string getNameForId(const std::string& id) const;
|
||||
virtual std::string getIdForName(const std::string& name) const;
|
||||
|
||||
private:
|
||||
void mapName(const kiwix::Library& lib, std::string name, std::string id);
|
||||
};
|
||||
|
||||
class UpdatableNameMapper : public NameMapper {
|
||||
typedef std::shared_ptr<NameMapper> NameMapperHandle;
|
||||
public:
|
||||
UpdatableNameMapper(std::shared_ptr<Library> library, bool withAlias);
|
||||
|
||||
virtual std::string getNameForId(const std::string& id) const;
|
||||
virtual std::string getIdForName(const std::string& name) const;
|
||||
|
||||
void update();
|
||||
|
||||
private:
|
||||
NameMapperHandle currentNameMapper() const;
|
||||
|
||||
private:
|
||||
mutable std::mutex mutex;
|
||||
std::shared_ptr<Library> library;
|
||||
NameMapperHandle nameMapper;
|
||||
const bool withAlias;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,4 @@
|
||||
/*
|
||||
* Copyright 2023 Nikhil Tanwar <2002nikhiltanwar@gmail.com>
|
||||
* Copyright 2017 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -18,30 +17,58 @@
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_LIBRARY_DUMPER_H
|
||||
#define KIWIX_LIBRARY_DUMPER_H
|
||||
#ifndef KIWIX_OPDS_DUMPER_H
|
||||
#define KIWIX_OPDS_DUMPER_H
|
||||
|
||||
#include <time.h>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
#include "common/base64.h"
|
||||
#include "common/pathTools.h"
|
||||
#include "common/regexTools.h"
|
||||
#include "library.h"
|
||||
#include "name_mapper.h"
|
||||
#include <mustache.hpp>
|
||||
#include "reader.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
/**
|
||||
* A base class to dump Library in various formats.
|
||||
* A tool to dump a `Library` into a opds stream.
|
||||
*
|
||||
*/
|
||||
class LibraryDumper
|
||||
class OPDSDumper
|
||||
{
|
||||
public:
|
||||
LibraryDumper(const Library* library, const NameMapper* NameMapper);
|
||||
~LibraryDumper();
|
||||
OPDSDumper() = default;
|
||||
OPDSDumper(Library* library);
|
||||
~OPDSDumper();
|
||||
|
||||
void setLibraryId(const std::string& id) { this->libraryId = id;}
|
||||
/**
|
||||
* Dump the OPDS feed.
|
||||
*
|
||||
* @param id The id of the library.
|
||||
* @return The OPDS feed.
|
||||
*/
|
||||
std::string dumpOPDSFeed(const std::vector<std::string>& bookIds);
|
||||
|
||||
/**
|
||||
* Set the id of the opds stream.
|
||||
*
|
||||
* @param id the id to use.
|
||||
*/
|
||||
void setId(const std::string& id) { this->id = id;}
|
||||
|
||||
/**
|
||||
* Set the title oft the opds stream.
|
||||
*
|
||||
* @param title the title to use.
|
||||
*/
|
||||
void setTitle(const std::string& title) { this->title = title; }
|
||||
|
||||
/**
|
||||
* Set the root location used when generating url.
|
||||
@@ -51,11 +78,11 @@ class LibraryDumper
|
||||
void setRootLocation(const std::string& rootLocation) { this->rootLocation = rootLocation; }
|
||||
|
||||
/**
|
||||
* Set the URL for accessing book content
|
||||
* Set the search url.
|
||||
*
|
||||
* @param url the URL of the /content endpoint of the content server
|
||||
* @param searchUrl the search url to use.
|
||||
*/
|
||||
void setContentAccessUrl(const std::string& url) { this->contentAccessUrl = url; }
|
||||
void setSearchDescriptionUrl(const std::string& searchDescriptionUrl) { this->searchDescriptionUrl = searchDescriptionUrl; }
|
||||
|
||||
/**
|
||||
* Set some informations about the search results.
|
||||
@@ -67,33 +94,27 @@ class LibraryDumper
|
||||
void setOpenSearchInfo(int totalResult, int startIndex, int count);
|
||||
|
||||
/**
|
||||
* Sets user default language
|
||||
* Set the library to dump.
|
||||
*
|
||||
* @param userLang the user language to be set
|
||||
* @param library The library to dump.
|
||||
*/
|
||||
void setUserLanguage(std::string userLang) { this->m_userLang = userLang; }
|
||||
|
||||
/**
|
||||
* Get the data of categories
|
||||
*/
|
||||
kainjow::mustache::list getCategoryData() const;
|
||||
|
||||
/**
|
||||
* Get the data of languages
|
||||
*/
|
||||
kainjow::mustache::list getLanguageData() const;
|
||||
void setLibrary(Library* library) { this->library = library; }
|
||||
|
||||
protected:
|
||||
const kiwix::Library* const library;
|
||||
const kiwix::NameMapper* const nameMapper;
|
||||
std::string libraryId;
|
||||
kiwix::Library* library;
|
||||
std::string id;
|
||||
std::string title;
|
||||
std::string date;
|
||||
std::string rootLocation;
|
||||
std::string contentAccessUrl;
|
||||
std::string m_userLang;
|
||||
std::string searchDescriptionUrl;
|
||||
int m_totalResults;
|
||||
int m_startIndex;
|
||||
int m_count;
|
||||
bool m_isSearchResult = false;
|
||||
|
||||
private:
|
||||
pugi::xml_node handleBook(Book book, pugi::xml_node root_node);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // KIWIX_LIBRARY_DUMPER_H
|
||||
#endif // KIWIX_OPDS_DUMPER_H
|
||||
505
include/reader.h
Normal file
505
include/reader.h
Normal file
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* Copyright 2011 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_READER_H
|
||||
#define KIWIX_READER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <zim/article.h>
|
||||
#include <zim/file.h>
|
||||
#include <zim/fileiterator.h>
|
||||
#include <zim/zim.h>
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "common.h"
|
||||
#include "entry.h"
|
||||
#include "common/pathTools.h"
|
||||
#include "common/stringTools.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
/**
|
||||
* The Reader class is the class who allow to get an entry content from a zim
|
||||
* file.
|
||||
*/
|
||||
class Reader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a Reader to read a zim file specified by zimFilePath.
|
||||
*
|
||||
* @param zimFilePath The path to the zim file to read.
|
||||
* The zim file can be splitted (.zimaa, .zimab, ...).
|
||||
* In this case, the file path must still point to the
|
||||
* unsplitted path as if the file were not splitted
|
||||
* (.zim extesion).
|
||||
*/
|
||||
Reader(const string zimFilePath);
|
||||
~Reader();
|
||||
|
||||
/**
|
||||
* Get the number of "displayable" entries in the zim file.
|
||||
*
|
||||
* @return If the zim file has a /M/Counter metadata, return the number of
|
||||
* entries with the 'text/html' MIMEtype specified in the metadata.
|
||||
* Else return the number of entries in the 'A' namespace.
|
||||
*/
|
||||
unsigned int getArticleCount() const;
|
||||
|
||||
/**
|
||||
* Get the number of media in the zim file.
|
||||
*
|
||||
* @return If the zim file has a /M/Counter metadata, return the number of
|
||||
* entries with the 'image/jpeg', 'image/gif' and 'image/png' in
|
||||
* the metadata.
|
||||
* Else return the number of entries in the 'I' namespace.
|
||||
*/
|
||||
unsigned int getMediaCount() const;
|
||||
|
||||
/**
|
||||
* Get the number of all entries in the zim file.
|
||||
*
|
||||
* @return Return the number of all the entries, whatever their MIMEtype or
|
||||
* their namespace.
|
||||
*/
|
||||
unsigned int getGlobalCount() const;
|
||||
|
||||
/**
|
||||
* Get the path of the zim file.
|
||||
*
|
||||
* @return the path of the zim file as given in the constructor.
|
||||
*/
|
||||
string getZimFilePath() const;
|
||||
|
||||
/**
|
||||
* Get the Id of the zim file.
|
||||
*
|
||||
* @return The uuid stored in the zim file.
|
||||
*/
|
||||
string getId() const;
|
||||
|
||||
/**
|
||||
* Get the url of a random page.
|
||||
*
|
||||
* Deprecated : Use `getRandomPage` instead.
|
||||
*
|
||||
* @return Url of a random page. The page is picked from all entries in
|
||||
* the 'A' namespace.
|
||||
* The main page is excluded from the potential results.
|
||||
*/
|
||||
DEPRECATED string getRandomPageUrl() const;
|
||||
|
||||
/**
|
||||
* Get a random page.
|
||||
*
|
||||
* @return A random Entry. The entry is picked from all entries in
|
||||
* the 'A' namespace.
|
||||
* The main entry is excluded from the potential results.
|
||||
*/
|
||||
Entry getRandomPage() const;
|
||||
|
||||
/**
|
||||
* Get the url of the first page.
|
||||
*
|
||||
* Deprecated : Use `getFirstPage` instead.
|
||||
*
|
||||
* @return Url of the first entry in the 'A' namespace.
|
||||
*/
|
||||
DEPRECATED string getFirstPageUrl() const;
|
||||
|
||||
/**
|
||||
* Get the entry of the first page.
|
||||
*
|
||||
* @return The first entry in the 'A' namespace.
|
||||
*/
|
||||
Entry getFirstPage() const;
|
||||
|
||||
/**
|
||||
* Get the url of the main page.
|
||||
*
|
||||
* Deprecated : Use `getMainPage` instead.
|
||||
*
|
||||
* @return Url of the main page as specified in the zim file.
|
||||
*/
|
||||
DEPRECATED string getMainPageUrl() const;
|
||||
|
||||
/**
|
||||
* Get the entry of the main page.
|
||||
*
|
||||
* @return Entry of the main page as specified in the zim file.
|
||||
*/
|
||||
Entry getMainPage() const;
|
||||
|
||||
/**
|
||||
* Get the content of a metadata.
|
||||
*
|
||||
* @param[in] name The name of the metadata.
|
||||
* @param[out] value The value will be set to the content of the metadata.
|
||||
* @return True if it was possible to get the content of the metadata.
|
||||
*/
|
||||
bool getMetatag(const string& name, string& value) const;
|
||||
|
||||
/**
|
||||
* Get the title of the zim file.
|
||||
*
|
||||
* @return The title of zim file as specified in the zim metadata.
|
||||
* If no title has been set, return a title computed from the
|
||||
* file path.
|
||||
*/
|
||||
string getTitle() const;
|
||||
|
||||
/**
|
||||
* Get the description of the zim file.
|
||||
*
|
||||
* @return The description of the zim file as specified in the zim metadata.
|
||||
* If no description has been set, return the subtitle.
|
||||
*/
|
||||
string getDescription() const;
|
||||
|
||||
/**
|
||||
* Get the language of the zim file.
|
||||
*
|
||||
* @return The language of the zim file as specified in the zim metadata.
|
||||
*/
|
||||
string getLanguage() const;
|
||||
|
||||
/**
|
||||
* Get the name of the zim file.
|
||||
*
|
||||
* @return The name of the zim file as specified in the zim metadata.
|
||||
*/
|
||||
string getName() const;
|
||||
|
||||
/**
|
||||
* Get the tags of the zim file.
|
||||
*
|
||||
* @return The tags of the zim file as specified in the zim metadata.
|
||||
*/
|
||||
string getTags() const;
|
||||
|
||||
/**
|
||||
* Get the date of the zim file.
|
||||
*
|
||||
* @return The date of the zim file as specified in the zim metadata.
|
||||
*/
|
||||
string getDate() const;
|
||||
|
||||
/**
|
||||
* Get the creator of the zim file.
|
||||
*
|
||||
* @return The creator of the zim file as specified in the zim metadata.
|
||||
*/
|
||||
string getCreator() const;
|
||||
|
||||
/**
|
||||
* Get the publisher of the zim file.
|
||||
*
|
||||
* @return The publisher of the zim file as specified in the zim metadata.
|
||||
*/
|
||||
string getPublisher() const;
|
||||
|
||||
/**
|
||||
* Get the origId of the zim file.
|
||||
*
|
||||
* The origId is only used in the case of patch zim file and is the Id
|
||||
* of the original zim file.
|
||||
*
|
||||
* @return The origId of the zim file as specified in the zim metadata.
|
||||
*/
|
||||
string getOrigId() const;
|
||||
|
||||
/**
|
||||
* Get the favicon of the zim file.
|
||||
*
|
||||
* @param[out] content The content of the favicon.
|
||||
* @param[out] mimeType The mimeType of the favicon.
|
||||
* @return True if a favicon has been found.
|
||||
*/
|
||||
bool getFavicon(string& content, string& mimeType) const;
|
||||
|
||||
/**
|
||||
* Get an entry associated to an path.
|
||||
*
|
||||
* @param path The path of the entry.
|
||||
* @return The entry.
|
||||
* @throw NoEntry If no entry correspond to the path.
|
||||
*/
|
||||
Entry getEntryFromPath(const std::string& path) const;
|
||||
|
||||
/**
|
||||
* Get an entry associated to an url encoded path.
|
||||
*
|
||||
* Equivalent to `getEntryFromPath(urlDecode(path));`
|
||||
*
|
||||
* @param path The url encoded path.
|
||||
* @return The entry.
|
||||
* @throw NoEntry If no entry correspond to the path.
|
||||
*/
|
||||
Entry getEntryFromEncodedPath(const std::string& path) const;
|
||||
|
||||
/**
|
||||
* Get un entry associated to a title.
|
||||
*
|
||||
* @param title The title.
|
||||
* @return The entry
|
||||
* throw NoEntry If no entry correspond to the url.
|
||||
*/
|
||||
Entry getEntryFromTitle(const std::string& title) const;
|
||||
|
||||
/**
|
||||
* Get the url of a page specified by a title.
|
||||
*
|
||||
* @param[in] title the title of the page.
|
||||
* @param[out] url the url of the page.
|
||||
* @return True if the page can be found.
|
||||
*/
|
||||
DEPRECATED bool getPageUrlFromTitle(const string& title, string& url) const;
|
||||
|
||||
/**
|
||||
* Get the mimetype of a entry specified by a url.
|
||||
*
|
||||
* @param[in] url the url of the entry.
|
||||
* @param[out] mimeType the mimeType of the entry.
|
||||
* @return True if the mimeType has been found.
|
||||
*/
|
||||
DEPRECATED bool getMimeTypeByUrl(const string& url, string& mimeType) const;
|
||||
|
||||
/**
|
||||
* Get the content of an entry specifed by a url.
|
||||
*
|
||||
* Alias to `getContentByEncodedUrl`
|
||||
*/
|
||||
DEPRECATED bool getContentByUrl(const string& url,
|
||||
string& content,
|
||||
string& title,
|
||||
unsigned int& contentLength,
|
||||
string& contentType) const;
|
||||
|
||||
/**
|
||||
* Get the content of an entry specified by a url encoded url.
|
||||
*
|
||||
* Equivalent to getContentByDecodedUrl(urlDecode(url), ...).
|
||||
*/
|
||||
DEPRECATED bool getContentByEncodedUrl(const string& url,
|
||||
string& content,
|
||||
string& title,
|
||||
unsigned int& contentLength,
|
||||
string& contentType,
|
||||
string& baseUrl) const;
|
||||
|
||||
/**
|
||||
* Get the content of an entry specified by an url encoded url.
|
||||
*
|
||||
* Equivalent to getContentByEncodedUrl but without baseUrl.
|
||||
*/
|
||||
DEPRECATED bool getContentByEncodedUrl(const string& url,
|
||||
string& content,
|
||||
string& title,
|
||||
unsigned int& contentLength,
|
||||
string& contentType) const;
|
||||
|
||||
/**
|
||||
* Get the content of an entry specified by a url.
|
||||
*
|
||||
* @param[in] url The url of the entry.
|
||||
* @param[out] content The content of the entry.
|
||||
* @param[out] title the title of the entry.
|
||||
* @param[out] contentLength The size of the entry (size of content).
|
||||
* @param[out] contentType The mimeType of the entry.
|
||||
* @param[out] baseUrl Return the true url of the entry.
|
||||
* If the specified entry is a redirection, contains
|
||||
* the url of the targeted entry.
|
||||
* @return True if the entry has been found.
|
||||
*/
|
||||
DEPRECATED bool getContentByDecodedUrl(const string& url,
|
||||
string& content,
|
||||
string& title,
|
||||
unsigned int& contentLength,
|
||||
string& contentType,
|
||||
string& baseUrl) const;
|
||||
/**
|
||||
* Get the content of an entry specified by a url.
|
||||
*
|
||||
* Equivalent to getContentByDecodedUrl but withou the baseUrl.
|
||||
*/
|
||||
DEPRECATED bool getContentByDecodedUrl(const string& url,
|
||||
string& content,
|
||||
string& title,
|
||||
unsigned int& contentLength,
|
||||
string& contentType) const;
|
||||
|
||||
/**
|
||||
* Search for entries with title starting with prefix (case sensitive).
|
||||
*
|
||||
* Suggestions are stored in an internal vector and can be retrieved using
|
||||
* `getNextSuggestion` method.
|
||||
*
|
||||
* @param prefix The prefix to search.
|
||||
* @param suggestionsCount How many suggestions to search for.
|
||||
* @param reset If true, remove previous suggestions in the internal vector.
|
||||
* If false, add suggestions to the internal vector
|
||||
* (until internal vector size is suggestionCount (or no more
|
||||
* suggestion))
|
||||
* @return True if some suggestions where added to the internal vector.
|
||||
*/
|
||||
bool searchSuggestions(const string& prefix,
|
||||
unsigned int suggestionsCount,
|
||||
const bool reset = true);
|
||||
|
||||
/**
|
||||
* Search for entries for the given prefix.
|
||||
*
|
||||
* If the zim file has a internal fulltext index, the suggestions will be
|
||||
* searched using it.
|
||||
* Else the suggestions will be search using `searchSuggestions` while trying
|
||||
* to be smart about case sensitivity (using `getTitleVariants`).
|
||||
*
|
||||
* In any case, suggestions are stored in an internal vector and can be
|
||||
* retrieved using `getNextSuggestion` method.
|
||||
* The internal vector will be reset.
|
||||
*
|
||||
* @param prefix The prefix to search for.
|
||||
* @param suggestionsCount How many suggestions to search for.
|
||||
*/
|
||||
bool searchSuggestionsSmart(const string& prefix,
|
||||
unsigned int suggestionsCount);
|
||||
|
||||
/**
|
||||
* Check if the url exists in the zim file.
|
||||
*
|
||||
* Deprecated : Use `pathExists` instead.
|
||||
*
|
||||
* @param url the url to check.
|
||||
* @return True if the url exits in the zim file.
|
||||
*/
|
||||
DEPRECATED bool urlExists(const string& url) const;
|
||||
|
||||
/**
|
||||
* Check if the path exists in the zim file.
|
||||
*
|
||||
* @param path the path to check.
|
||||
* @return True if the path exists in the zim file.
|
||||
*/
|
||||
bool pathExists(const string& path) const;
|
||||
|
||||
/**
|
||||
* Check if the zim file has a embedded fulltext index.
|
||||
*
|
||||
* @return True if the zim file has a embedded fulltext index
|
||||
* and is not split (else the fulltext is not accessible).
|
||||
*/
|
||||
bool hasFulltextIndex() const;
|
||||
|
||||
/**
|
||||
* Get potential case title variations for a title.
|
||||
*
|
||||
* @param title a title.
|
||||
* @return the list of variantions.
|
||||
*/
|
||||
std::vector<std::string> getTitleVariants(const std::string& title) const;
|
||||
|
||||
/**
|
||||
* Get the next suggestion title.
|
||||
*
|
||||
* @param[out] title the title of the suggestion.
|
||||
* @return True if title has been set.
|
||||
*/
|
||||
bool getNextSuggestion(string& title);
|
||||
|
||||
/**
|
||||
* Get the next suggestion title and url.
|
||||
*
|
||||
* @param[out] title the title of the suggestion.
|
||||
* @param[out] url the url of the suggestion.
|
||||
* @return True if title and url have been set.
|
||||
*/
|
||||
bool getNextSuggestion(string& title, string& url);
|
||||
|
||||
/**
|
||||
* Get if we can check zim file integrity (has a checksum).
|
||||
*
|
||||
* @return True if zim file have a checksum.
|
||||
*/
|
||||
bool canCheckIntegrity() const;
|
||||
|
||||
/**
|
||||
* Check is zim file is corrupted.
|
||||
*
|
||||
* @return True if zim file is corrupted.
|
||||
*/
|
||||
bool isCorrupted() const;
|
||||
|
||||
/**
|
||||
* Parse a full url into a namespace and url.
|
||||
*
|
||||
* @param[in] url The full url ("/N/url").
|
||||
* @param[out] ns The namespace (N).
|
||||
* @param[out] title The url (url).
|
||||
* @return True
|
||||
*/
|
||||
DEPRECATED bool parseUrl(const string& url, char* ns, string& title) const;
|
||||
|
||||
/**
|
||||
* Return the total size of the zim file.
|
||||
*
|
||||
* If zim file is split, return the sum of all parts' size.
|
||||
*
|
||||
* @return Size of the size file is KiB.
|
||||
*/
|
||||
unsigned int getFileSize() const;
|
||||
|
||||
/**
|
||||
* Get the zim file handler.
|
||||
*
|
||||
* @return The libzim file handler.
|
||||
*/
|
||||
zim::File* getZimFileHandler() const;
|
||||
|
||||
/**
|
||||
* Get the zim article object associated to a url.
|
||||
*
|
||||
* @param[in] url The url of the article.
|
||||
* @param[out] article The libzim article object.
|
||||
* @return True if the url is good (article.good()).
|
||||
*/
|
||||
DEPRECATED bool getArticleObjectByDecodedUrl(const string& url,
|
||||
zim::Article& article) const;
|
||||
|
||||
protected:
|
||||
zim::File* zimFileHandler;
|
||||
zim::size_type firstArticleOffset;
|
||||
zim::size_type lastArticleOffset;
|
||||
zim::size_type nsACount;
|
||||
zim::size_type nsICount;
|
||||
std::string zimFilePath;
|
||||
|
||||
std::vector<std::vector<std::string>> suggestions;
|
||||
std::vector<std::vector<std::string>>::iterator suggestionsOffset;
|
||||
|
||||
private:
|
||||
std::map<const std::string, unsigned int> parseCounterMetadata() const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_SEARCH_RENDERER_H
|
||||
#define KIWIX_SEARCH_RENDERER_H
|
||||
|
||||
#include <string>
|
||||
#include <zim/search.h>
|
||||
#include "library.h"
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
class NameMapper;
|
||||
/**
|
||||
* The SearcherRenderer class is used to render a search result to a html page.
|
||||
*/
|
||||
class SearchRenderer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct a SearchRenderer from a SearchResultSet.
|
||||
*
|
||||
* @param srs The `SearchResultSet` to render.
|
||||
* @param start The start offset used for the srs.
|
||||
* @param estimatedResultCount The estimatedResultCount of the whole search
|
||||
*/
|
||||
SearchRenderer(zim::SearchResultSet srs, unsigned int start, unsigned int estimatedResultCount);
|
||||
|
||||
~SearchRenderer();
|
||||
|
||||
/**
|
||||
* Set the search pattern used to do the search
|
||||
*/
|
||||
void setSearchPattern(const std::string& pattern);
|
||||
|
||||
/**
|
||||
* Set the querystring used to select books
|
||||
*/
|
||||
void setSearchBookQuery(const std::string& bookQuery);
|
||||
|
||||
/**
|
||||
* Set protocol prefix.
|
||||
*/
|
||||
void setProtocolPrefix(const std::string& prefix);
|
||||
|
||||
/**
|
||||
* Set search protocol prefix.
|
||||
*/
|
||||
void setSearchProtocolPrefix(const std::string& prefix);
|
||||
|
||||
/**
|
||||
* set result count per page
|
||||
*/
|
||||
void setPageLength(unsigned int pageLength){
|
||||
this->pageLength = pageLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* set user language
|
||||
*/
|
||||
void setUserLang(const std::string& lang){
|
||||
this->userlang = lang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the html page with the resutls of the search.
|
||||
*
|
||||
* @param mapper The `NameMapper` to use to do the rendering.
|
||||
* @param library The `Library` to use to look up book details for search results.
|
||||
May be nullptr. In this case, bookName is not set in the rendered string.
|
||||
* @return The html string
|
||||
*/
|
||||
std::string getHtml(const NameMapper& mapper, const Library* library);
|
||||
|
||||
/**
|
||||
* Generate the xml page with the resutls of the search.
|
||||
*
|
||||
* @param mapper The `NameMapper` to use to do the rendering.
|
||||
* @param library The `Library` to use to look up book details for search results.
|
||||
May be nullptr. In this case, bookName is not set in the rendered string.
|
||||
* @return The xml string
|
||||
*/
|
||||
std::string getXml(const NameMapper& mapper, const Library* library);
|
||||
|
||||
protected: // function
|
||||
std::string renderTemplate(const std::string& tmpl_str, const NameMapper& mapper, const Library *library);
|
||||
|
||||
protected:
|
||||
std::string beautifyInteger(const unsigned int number);
|
||||
zim::SearchResultSet m_srs;
|
||||
std::string searchBookQuery;
|
||||
std::string searchPattern;
|
||||
std::string protocolPrefix;
|
||||
std::string searchProtocolPrefix;
|
||||
unsigned int pageLength;
|
||||
unsigned int estimatedResultCount;
|
||||
unsigned int resultStart;
|
||||
std::string userlang = "en";
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
230
include/searcher.h
Normal file
230
include/searcher.h
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright 2011 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_SEARCHER_H
|
||||
#define KIWIX_SEARCHER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unicode/putil.h>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <locale>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <vector>
|
||||
#include "common/pathTools.h"
|
||||
#include "common/stringTools.h"
|
||||
#include "kiwix_config.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
class Reader;
|
||||
class Result
|
||||
{
|
||||
public:
|
||||
virtual ~Result(){};
|
||||
virtual std::string get_url() = 0;
|
||||
virtual std::string get_title() = 0;
|
||||
virtual int get_score() = 0;
|
||||
virtual std::string get_snippet() = 0;
|
||||
virtual std::string get_content() = 0;
|
||||
virtual int get_wordCount() = 0;
|
||||
virtual int get_size() = 0;
|
||||
virtual int get_readerIndex() = 0;
|
||||
};
|
||||
|
||||
struct SearcherInternal;
|
||||
/**
|
||||
* The Searcher class is reponsible to do different kind of search using the
|
||||
* fulltext index.
|
||||
*
|
||||
* Historically, there are two kind of fulltext index :
|
||||
* - The legacy one, is the external fulltext index. A directory stored outside
|
||||
* of the zim file.
|
||||
* - The new one, a embedded fulltext index in the zim file.
|
||||
*
|
||||
* Legacy external fulltext index has to be considered as obsolet format with
|
||||
* less functionnalities:
|
||||
* - No multi zim search ;
|
||||
* - No geo_search ;
|
||||
* - No suggestions search ;
|
||||
*
|
||||
* To reflect this, there is two Search creation "API":
|
||||
* - One for the external fulltext index, using the constructor taking a
|
||||
* xapianDirectoryPath) ;
|
||||
* - One for the embedded fulltext index, using a "empty" constructor and the
|
||||
* `add_reader` method".
|
||||
*
|
||||
* On top of that, the Searcher may (if compiled with ctpp2) be used to
|
||||
* generate a html page for the search result. This use a template that need a
|
||||
* humanReaderName. This feature is only used by kiwix-serve and this should be
|
||||
* move outside of Searcher (and with a better API). If you don't use the html
|
||||
* rendering (getHtml method), you better should simply ignore the different
|
||||
* humanReadeableName attributes (or give an empty string).
|
||||
*/
|
||||
class Searcher
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The default constructor.
|
||||
*
|
||||
* @param humanReadableName The global zim's humanReadableName.
|
||||
* Used to generate pagination links.
|
||||
*/
|
||||
Searcher(const string& humanReadableName = "");
|
||||
|
||||
/**
|
||||
* The constructor for legacy external fulltext index.
|
||||
*
|
||||
* @param xapianDirectoryPath The path to the external index directory.
|
||||
* @param reader The reader associated to the external index.
|
||||
* It will be used retrive the article content or generate
|
||||
* the snippet.
|
||||
* @param humanReadableName The humanReadableName for the zim.
|
||||
*/
|
||||
Searcher(const string& xapianDirectoryPath,
|
||||
Reader* reader,
|
||||
const string& humanReadableName);
|
||||
~Searcher();
|
||||
|
||||
/**
|
||||
* Add a reader (containing embedded fulltext index) to the search.
|
||||
*
|
||||
* @param reader The Reader for the zim containing the fulltext index.
|
||||
* @param humanReaderName The human readable name of the reader.
|
||||
* @return true if the reader has been added.
|
||||
* false if the reader cannot be added (no embedded fulltext index present)
|
||||
*/
|
||||
bool add_reader(Reader* reader, const std::string& humanReaderName);
|
||||
|
||||
/**
|
||||
* Start a search on the zim associated to the Searcher.
|
||||
*
|
||||
* Search results should be retrived using the getNextResult method.
|
||||
*
|
||||
* @param search The search query.
|
||||
* @param resultStart the start offset of the search results (used for pagination).
|
||||
* @param resultEnd the end offset of the search results (used for pagination).
|
||||
* @param verbose print some info on stdout if true.
|
||||
*/
|
||||
void search(std::string& search,
|
||||
unsigned int resultStart,
|
||||
unsigned int resultEnd,
|
||||
const bool verbose = false);
|
||||
|
||||
/**
|
||||
* Start a geographique search.
|
||||
* The search return result for entry in a disc of center latitude/longitude
|
||||
* and radius distance.
|
||||
*
|
||||
* Search results should be retrived using the getNextResult method.
|
||||
*
|
||||
* @param latitude The latitude of the center point.
|
||||
* @param longitude The longitude of the center point.
|
||||
* @param distance The radius of the disc.
|
||||
* @param resultStart the start offset of the search results (used for pagination).
|
||||
* @param resultEnd the end offset of the search results (used for pagination).
|
||||
* @param verbose print some info on stdout if true.
|
||||
*/
|
||||
void geo_search(float latitude, float longitude, float distance,
|
||||
unsigned int resultStart,
|
||||
unsigned int resultEnd,
|
||||
const bool verbose = false);
|
||||
|
||||
/**
|
||||
* Start a suggestion search.
|
||||
* The search made depend of the "version" of the embedded index.
|
||||
* - If the index is newer enough and have a title namespace, the search is
|
||||
* made in the titles only.
|
||||
* - Else the search is made on the whole article content.
|
||||
* In any case, the search is made "partial" (as adding '*' at the end of the query)
|
||||
*
|
||||
* @param search The search query.
|
||||
* @param verbose print some info on stdout if true.
|
||||
*/
|
||||
void suggestions(std::string& search, const bool verbose = false);
|
||||
|
||||
/**
|
||||
* Get the next result of a started search.
|
||||
* This is the method to use to loop hover the search results.
|
||||
*/
|
||||
Result* getNextResult();
|
||||
|
||||
/**
|
||||
* Restart the previous search.
|
||||
* Next call to getNextResult will return the first result.
|
||||
*/
|
||||
void restart_search();
|
||||
|
||||
/**
|
||||
* Get a estimation of the result count.
|
||||
*/
|
||||
unsigned int getEstimatedResultCount();
|
||||
|
||||
/**
|
||||
* Set protocol prefix.
|
||||
* Only used by getHtml.
|
||||
*/
|
||||
bool setProtocolPrefix(const std::string prefix);
|
||||
|
||||
/**
|
||||
* Set search protocol prefix.
|
||||
* Only used by getHtml.
|
||||
*/
|
||||
bool setSearchProtocolPrefix(const std::string prefix);
|
||||
|
||||
#ifdef ENABLE_CTPP2
|
||||
/**
|
||||
* Generate the html page with the resutls of the search.
|
||||
*/
|
||||
string getHtml();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
std::string beautifyInteger(const unsigned int number);
|
||||
void closeIndex();
|
||||
void searchInIndex(string& search,
|
||||
const unsigned int resultStart,
|
||||
const unsigned int resultEnd,
|
||||
const bool verbose = false);
|
||||
|
||||
std::vector<Reader*> readers;
|
||||
std::vector<std::string> humanReaderNames;
|
||||
SearcherInternal* internal;
|
||||
std::string searchPattern;
|
||||
std::string protocolPrefix;
|
||||
std::string searchProtocolPrefix;
|
||||
unsigned int resultCountPerPage;
|
||||
unsigned int estimatedResultCount;
|
||||
unsigned int resultStart;
|
||||
unsigned int resultEnd;
|
||||
std::string contentHumanReadableId;
|
||||
|
||||
private:
|
||||
void reset();
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_SERVER_H
|
||||
#define KIWIX_SERVER_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "tools.h"
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
class Library;
|
||||
class NameMapper;
|
||||
class InternalServer;
|
||||
|
||||
class Server {
|
||||
public:
|
||||
/**
|
||||
* The default constructor.
|
||||
*
|
||||
* @param library The library to serve.
|
||||
*/
|
||||
Server(std::shared_ptr<Library> library, std::shared_ptr<NameMapper> nameMapper=nullptr);
|
||||
|
||||
virtual ~Server();
|
||||
|
||||
/**
|
||||
* Serve the content.
|
||||
*/
|
||||
bool start();
|
||||
|
||||
/**
|
||||
* Stop the daemon.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
void setRoot(const std::string& root);
|
||||
void setAddress(const std::string& addr);
|
||||
void setPort(int port) { m_port = port; }
|
||||
void setNbThreads(int threads) { m_nbThreads = threads; }
|
||||
void setMultiZimSearchLimit(unsigned int limit) { m_multizimSearchLimit = limit; }
|
||||
void setIpConnectionLimit(int limit) { m_ipConnectionLimit = limit; }
|
||||
void setVerbose(bool verbose) { m_verbose = verbose; }
|
||||
void setIndexTemplateString(const std::string& indexTemplateString) { m_indexTemplateString = indexTemplateString; }
|
||||
void setTaskbar(bool withTaskbar, bool withLibraryButton)
|
||||
{ m_withTaskbar = withTaskbar; m_withLibraryButton = withLibraryButton; }
|
||||
void setBlockExternalLinks(bool blockExternalLinks)
|
||||
{ m_blockExternalLinks = blockExternalLinks; }
|
||||
void setCatalogOnlyMode(bool enable) { m_catalogOnlyMode = enable; }
|
||||
void setContentServerUrl(std::string url) { m_contentServerUrl = url; }
|
||||
void setIpMode(IpMode mode) { m_ipMode = mode; }
|
||||
int getPort() const;
|
||||
IpAddress getAddress() const;
|
||||
IpMode getIpMode() const;
|
||||
std::vector<std::string> getServerAccessUrls() const;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Library> mp_library;
|
||||
std::shared_ptr<NameMapper> mp_nameMapper;
|
||||
std::string m_root = "";
|
||||
IpAddress m_addr;
|
||||
std::string m_indexTemplateString = "";
|
||||
int m_port = 80;
|
||||
int m_nbThreads = 1;
|
||||
unsigned int m_multizimSearchLimit = 0;
|
||||
bool m_verbose = false;
|
||||
bool m_withTaskbar = true;
|
||||
bool m_withLibraryButton = true;
|
||||
bool m_blockExternalLinks = false;
|
||||
IpMode m_ipMode = IpMode::AUTO;
|
||||
int m_ipConnectionLimit = 0;
|
||||
bool m_catalogOnlyMode = false;
|
||||
std::string m_contentServerUrl;
|
||||
std::unique_ptr<InternalServer> mp_server;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 Veloman Yunkan
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_SPELLING_CORRECTION_H
|
||||
#define KIWIX_SPELLING_CORRECTION_H
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace zim
|
||||
{
|
||||
class Archive;
|
||||
}
|
||||
|
||||
namespace Xapian
|
||||
{
|
||||
class Database;
|
||||
}
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
class SpellingsDB
|
||||
{
|
||||
public: // functions
|
||||
SpellingsDB(const zim::Archive& archive, std::filesystem::path cacheDirPath);
|
||||
~SpellingsDB();
|
||||
|
||||
SpellingsDB(const SpellingsDB& ) = delete;
|
||||
void operator=(const SpellingsDB& ) = delete;
|
||||
|
||||
std::vector<std::string> getSpellingCorrections(const std::string& word, uint32_t maxCount) const;
|
||||
|
||||
private: // data
|
||||
std::unique_ptr<Xapian::Database> impl_;
|
||||
};
|
||||
|
||||
} // namespace kiwix
|
||||
|
||||
#endif // KIWIX_SPELLING_CORRECTION_H
|
||||
271
include/tools.h
271
include/tools.h
@@ -1,271 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_TOOLS_H
|
||||
#define KIWIX_TOOLS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
#include "common.h"
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
struct IpAddress
|
||||
{
|
||||
std::string addr; // IPv4 address
|
||||
std::string addr6; // IPv6 address
|
||||
};
|
||||
|
||||
typedef std::pair<std::string, std::string> LangNameCodePair;
|
||||
typedef std::vector<LangNameCodePair> FeedLanguages;
|
||||
typedef std::vector<std::string> FeedCategories;
|
||||
|
||||
/**
|
||||
* Return the current directory.
|
||||
*
|
||||
* @return the current directory (utf8 encoded)
|
||||
*/
|
||||
std::string getCurrentDirectory();
|
||||
|
||||
/** Return the path of the executable
|
||||
*
|
||||
* Some application may be packaged in auto extractible archive (Appimage) and the
|
||||
* real executable is different of the path of the archive.
|
||||
* If `realPathOnly` is true, return the path of the real executable instead of the
|
||||
* archive launched by the user.
|
||||
*
|
||||
* @param realPathOnly If we must return the real path of the executable.
|
||||
* @return the path of the executable (utf8 encoded)
|
||||
*/
|
||||
std::string getExecutablePath(bool realPathOnly = false);
|
||||
|
||||
/** Tell if the path is a relative path.
|
||||
*
|
||||
* This function is provided as a small helper. It is probably better to use native tools
|
||||
* to manipulate paths.
|
||||
*
|
||||
* @param path A utf8 encoded path.
|
||||
* @return true if the path is relative.
|
||||
*/
|
||||
bool isRelativePath(const std::string& path);
|
||||
|
||||
/** Append a path to another one.
|
||||
*
|
||||
* This function is provided as a small helper. It is probably better to use native tools
|
||||
* to manipulate paths.
|
||||
*
|
||||
* @param basePath the base path.
|
||||
* @param relativePath a path to add to the base path, must be a relative path.
|
||||
* @return The concatenation of the paths, using the right separator.
|
||||
*/
|
||||
std::string appendToDirectory(const std::string& basePath, const std::string& relativePath);
|
||||
|
||||
/** Remove the last element of a path.
|
||||
*
|
||||
* This function is provided as a small helper. It is probably better to use native tools
|
||||
* to manipulate paths.
|
||||
*
|
||||
* @param path a path.
|
||||
* @return The parent directory (or empty string if none).
|
||||
*/
|
||||
std::string removeLastPathElement(const std::string& path);
|
||||
|
||||
/** Get the last element of a path.
|
||||
*
|
||||
* This function is provided as a small helper. It is probably better to use native tools
|
||||
* to manipulate paths.
|
||||
*
|
||||
* @param path a path.
|
||||
* @return The base name of the path or empty string if none (ending with a separator).
|
||||
*/
|
||||
std::string getLastPathElement(const std::string& path);
|
||||
|
||||
/** Compute the absolute path of a relative path based on another one
|
||||
*
|
||||
* Equivalent to appendToDirectory followed by a normalization of the path.
|
||||
*
|
||||
* This function is provided as a small helper. It is probably better to use native tools
|
||||
* to manipulate paths.
|
||||
*
|
||||
* @param path the base path (if empty, current directory is taken).
|
||||
* @param relativePath the relative path.
|
||||
* @return a absolute path.
|
||||
*/
|
||||
std::string computeAbsolutePath(const std::string& path, const std::string& relativePath);
|
||||
|
||||
/** Compute the relative path of a path relative to another one
|
||||
*
|
||||
* This function is provided as a small helper. It is probably better to use native tools
|
||||
* to manipulate paths.
|
||||
*
|
||||
* @param path the base path.
|
||||
* @param absolutePath the absolute path to find the relative path for.
|
||||
* @return a relative path (pointing to absolutePath, relative to path).
|
||||
*/
|
||||
std::string computeRelativePath(const std::string& path, const std::string& absolutePath);
|
||||
|
||||
/** Sleep the current thread.
|
||||
*
|
||||
* This function is provided as a small helper. It is probably better to use native tools.
|
||||
*
|
||||
* @param milliseconds The number of milliseconds to wait for.
|
||||
*/
|
||||
void sleep(unsigned int milliseconds);
|
||||
|
||||
/** Split a string
|
||||
*
|
||||
* This function is provided as a small helper. It is probably better to use native tools.
|
||||
*
|
||||
* Assuming text = "foo:;bar;baz,oups;"
|
||||
*
|
||||
* split(text, ":;", true, true) => ["foo", ":", ";", "bar", ";", "baz,oups", ";"]
|
||||
* split(text, ":;", true, false) => ["foo", "bar", "baz,oups"] (default)
|
||||
* split(text, ":;", false, true) => ["foo", ":", "", ";", "bar", ";", "baz,oups", ";", ""]
|
||||
* split(text, ":;", false, false) => ["foo", "", "bar", "baz,oups", ""]
|
||||
*
|
||||
* @param str The string to split.
|
||||
* @param delims A string of potential delimiters.
|
||||
* Each charater in the string can be a individual delimiters.
|
||||
* @param dropEmpty true if empty part must be dropped from the result.
|
||||
* @param keepDelim true if delimiter must be included from the result.
|
||||
* @return a list of part (potentially containing delimiters)
|
||||
*/
|
||||
std::vector<std::string> split(const std::string& str, const std::string& delims, bool dropEmpty=true, bool keepDelim = false);
|
||||
|
||||
/** Convert language code from iso2 code to iso3
|
||||
*
|
||||
* This function is provided as a small helper. It is probably better to use native tools
|
||||
* to manipulate locales.
|
||||
*
|
||||
* @param a2code a iso2 code string.
|
||||
* @return the corresponding iso3 code.
|
||||
* @throw std::out_of_range if iso2 code is not known.
|
||||
*/
|
||||
std::string converta2toa3(const std::string& a2code);
|
||||
|
||||
/** Extracts content from given file.
|
||||
*
|
||||
* This function provides content of a file provided it's path.
|
||||
*
|
||||
* @param path The absolute path provided in string format.
|
||||
* @return Content of corresponding file in string format.
|
||||
*/
|
||||
std::string getFileContent(const std::string& path);
|
||||
|
||||
/** Checks if file exists.
|
||||
*
|
||||
* This function returns boolean stating if file exists.
|
||||
*
|
||||
* @param path The absolute path provided in string format.
|
||||
* @return Boolean representing if file exists or not.
|
||||
*/
|
||||
bool fileExists(const std::string& path);
|
||||
|
||||
/** Checks if file is readable.
|
||||
*
|
||||
* This function returns boolean stating if file is readable.
|
||||
*
|
||||
* @param path The absolute path provided in string format.
|
||||
* @return Boolean representing if file is readale or not.
|
||||
*/
|
||||
bool fileReadable(const std::string& path);
|
||||
|
||||
/** Provides mimetype from filename.
|
||||
*
|
||||
* This function provides mimetype from file-name.
|
||||
*
|
||||
* @param filename string containing filename.
|
||||
* @return mimetype from filename in string format.
|
||||
*/
|
||||
std::string getMimeTypeForFile(const std::string& filename);
|
||||
|
||||
/** Provides all available network interfaces
|
||||
*
|
||||
* This function provides the available IPv4 and IPv6 network interfaces
|
||||
* as a map from the interface name to its IPv4 and/or IPv6 address(es).
|
||||
*/
|
||||
std::map<std::string, IpAddress> getNetworkInterfacesIPv4Or6();
|
||||
|
||||
/** Provides all available IPv4 network interfaces
|
||||
*
|
||||
* This function provides the available IPv4 network interfaces
|
||||
* as a map from the interface name to its IPv4 address.
|
||||
*
|
||||
* Provided for backward compatibility with libkiwix v13.1.0.
|
||||
*/
|
||||
std::map<std::string, std::string> getNetworkInterfaces();
|
||||
|
||||
/** Provides the best IP address
|
||||
* This function provides the best IP addresses for both ipv4 and ipv6 protocols,
|
||||
* in an IpAddress struct, based on the list given by getNetworkInterfacesIPv4Or6()
|
||||
*/
|
||||
IpAddress getBestPublicIps();
|
||||
|
||||
/** Provides the best IPv4 adddress
|
||||
* Equivalent to getBestPublicIp(false). Provided for backward compatibility
|
||||
* with libkiwix v13.1.0.
|
||||
*/
|
||||
std::string getBestPublicIp();
|
||||
|
||||
/** Converts file size to human readable format.
|
||||
*
|
||||
* This function will convert a number to its equivalent size using units.
|
||||
*
|
||||
* @param number file size in bytes.
|
||||
* @return a human-readable string representation of the size, e.g., "2.3 KB", "1.8 MB", "5.2 GB".
|
||||
*/
|
||||
std::string beautifyFileSize(uint64_t number);
|
||||
|
||||
/**
|
||||
* Load languages stored in an OPDS stream.
|
||||
*
|
||||
* @param content the OPDS stream.
|
||||
* @return vector containing pairs of language code and their corresponding full language name.
|
||||
*/
|
||||
FeedLanguages readLanguagesFromFeed(const std::string& content);
|
||||
|
||||
/**
|
||||
* Load categories stored in an OPDS stream .
|
||||
*
|
||||
* @param content the OPDS stream.
|
||||
* @return vector containing category strings.
|
||||
*/
|
||||
FeedCategories readCategoriesFromFeed(const std::string& content);
|
||||
|
||||
/**
|
||||
* Retrieve the full language name associated with a given ISO 639-3 language code.
|
||||
*
|
||||
* @param lang ISO 639-3 language code.
|
||||
* @return full language name.
|
||||
*/
|
||||
std::string getLanguageSelfName(const std::string& lang);
|
||||
|
||||
/**
|
||||
* Slugifies the filename by converting any characters reserved by the operating
|
||||
* system to '_'. Note filename is only the file name and not a path.
|
||||
*
|
||||
* @param filename Valid UTF-8 encoded file name string.
|
||||
* @return slugified string.
|
||||
*/
|
||||
std::string getSlugifiedFileName(const std::string& filename);
|
||||
}
|
||||
#endif // KIWIX_TOOLS_H
|
||||
98
include/xapianSearcher.h
Normal file
98
include/xapianSearcher.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2011 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_XAPIAN_SEARCHER_H
|
||||
#define KIWIX_XAPIAN_SEARCHER_H
|
||||
|
||||
#include <xapian.h>
|
||||
#include "reader.h"
|
||||
#include "searcher.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
class XapianSearcher;
|
||||
|
||||
class XapianResult : public Result
|
||||
{
|
||||
public:
|
||||
XapianResult(XapianSearcher* searcher, Xapian::MSetIterator& iterator);
|
||||
virtual ~XapianResult(){};
|
||||
|
||||
virtual std::string get_url();
|
||||
virtual std::string get_title();
|
||||
virtual int get_score();
|
||||
virtual std::string get_snippet();
|
||||
virtual std::string get_content();
|
||||
virtual int get_wordCount();
|
||||
virtual int get_size();
|
||||
virtual int get_readerIndex() { return 0; };
|
||||
|
||||
private:
|
||||
XapianSearcher* searcher;
|
||||
Xapian::MSetIterator iterator;
|
||||
Xapian::Document document;
|
||||
};
|
||||
|
||||
class NoXapianIndexInZim : public exception
|
||||
{
|
||||
virtual const char* what() const throw()
|
||||
{
|
||||
return "There is no fulltext index in the zim file";
|
||||
}
|
||||
};
|
||||
|
||||
class XapianSearcher
|
||||
{
|
||||
friend class XapianResult;
|
||||
|
||||
public:
|
||||
XapianSearcher(const string& xapianDirectoryPath, Reader* reader);
|
||||
virtual ~XapianSearcher(){};
|
||||
void searchInIndex(string& search,
|
||||
const unsigned int resultStart,
|
||||
const unsigned int resultEnd,
|
||||
const bool verbose = false);
|
||||
virtual Result* getNextResult();
|
||||
void restart_search();
|
||||
|
||||
Xapian::MSet results;
|
||||
|
||||
protected:
|
||||
void closeIndex();
|
||||
void openIndex(const string& xapianDirectoryPath);
|
||||
void setup_queryParser();
|
||||
|
||||
Reader* reader;
|
||||
Xapian::Database readableDatabase;
|
||||
std::string language;
|
||||
std::string stopwords;
|
||||
Xapian::QueryParser queryParser;
|
||||
Xapian::Stem stemmer;
|
||||
Xapian::SimpleStopper stopper;
|
||||
Xapian::MSetIterator current_result;
|
||||
std::map<std::string, int> valuesmap;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
10
kiwix.pc.in
Normal file
10
kiwix.pc.in
Normal file
@@ -0,0 +1,10 @@
|
||||
prefix=@prefix@
|
||||
libdir=${prefix}/lib64
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libkiwix
|
||||
Description: A library that contains a lot of things used by used by other kiwix programs
|
||||
Version: @version@
|
||||
Requires: @requires@
|
||||
Libs: -L${libdir} -lkiwix @extra_libs@
|
||||
Cflags: -I${includedir}/ @extra_cflags@
|
||||
199
meson.build
199
meson.build
@@ -1,122 +1,135 @@
|
||||
project('libkiwix', 'cpp',
|
||||
version : '14.1.1',
|
||||
license : 'GPLv3+',
|
||||
default_options : ['c_std=c11', 'cpp_std=c++17', 'werror=true'])
|
||||
project('kiwix-lib', 'cpp',
|
||||
version : '3.0.3',
|
||||
license : 'GPL',
|
||||
default_options : ['c_std=c11', 'cpp_std=c++11', 'werror=true'])
|
||||
|
||||
compiler = meson.get_compiler('cpp')
|
||||
static_deps = get_option('static-linkage') or get_option('default_library') == 'static'
|
||||
extra_libs = []
|
||||
find_library_in_compiler = meson.version().version_compare('>=0.31.0')
|
||||
|
||||
# Atomics as compiled by GCC or clang can lead to external references to
|
||||
# functions depending on the type size and the platform. LLVM provides them in
|
||||
# 'libcompiler_rt', which clang normally automatically links in, while GNU
|
||||
# provides them in 'libatomic', which GCC *does not* link in automatically (but
|
||||
# this is probably going to change, see
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81358). Regardless of the setup
|
||||
# of the compiler driver itself (GCC or clang), we can thus assume that if some
|
||||
# atomic references can't be resolved, then 'libatomic' is missing.
|
||||
atomics_program = '''
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
volatile atomic_bool a_b(true);
|
||||
volatile atomic_ullong a_ull(-1);
|
||||
// Next two lines are to cover atomic<socket_t> from 'httplib.h'.
|
||||
volatile atomic<uint32_t> a_u32(-1);
|
||||
volatile atomic<uint64_t> a_u64(-1);
|
||||
|
||||
return atomic_load(&a_b) == false && atomic_load(&a_ull) == 0 &&
|
||||
atomic_load(&a_u32) == 0 && atomic_load(&a_u64) == 0;
|
||||
}
|
||||
'''
|
||||
if not compiler.links(atomics_program,
|
||||
name: 'compiler driver readily supports atomics')
|
||||
libatomic = compiler.find_library('atomic')
|
||||
compiler.links(atomics_program, name: 'atomics work with libatomic',
|
||||
dependencies: libatomic, required: true)
|
||||
extra_libs += ['-latomic']
|
||||
endif
|
||||
|
||||
# C++ std::thread is implemented using pthread on Linux by GCC, and on FreeBSD
|
||||
# for both GCC and LLVM.
|
||||
if (host_machine.system() == 'linux' and compiler.get_id() == 'gcc') or \
|
||||
host_machine.system() == 'freebsd'
|
||||
thread_dep = dependency('threads')
|
||||
static_deps = get_option('android') or get_option('default_library') == 'static'
|
||||
if get_option('android')
|
||||
extra_libs = ['-llog']
|
||||
else
|
||||
thread_dep = dependency('', required:false)
|
||||
extra_libs = []
|
||||
endif
|
||||
|
||||
thread_dep = dependency('threads')
|
||||
libicu_dep = dependency('icu-i18n', static:static_deps)
|
||||
if libicu_dep.version().version_compare('>= 76')
|
||||
libicu_deps = [libicu_dep, dependency('icu-uc', static:static_deps)]
|
||||
else
|
||||
libicu_deps = [libicu_dep]
|
||||
endif
|
||||
|
||||
libzim_dep = dependency('libzim', version : '>=4.0.0', static:static_deps)
|
||||
pugixml_dep = dependency('pugixml', static:static_deps)
|
||||
libcurl_dep = dependency('libcurl', static:static_deps)
|
||||
microhttpd_dep = dependency('libmicrohttpd', static:static_deps)
|
||||
zlib_dep = dependency('zlib', static:static_deps)
|
||||
xapian_dep = dependency('xapian-core', static:static_deps)
|
||||
|
||||
if compiler.has_header('mustache.hpp')
|
||||
extra_include = []
|
||||
elif compiler.has_header('mustache.hpp', args: '-I/usr/include/kainjow')
|
||||
extra_include = ['/usr/include/kainjow']
|
||||
else
|
||||
error('Cannot found header mustache.hpp')
|
||||
endif
|
||||
|
||||
libzim_dep = dependency('libzim', version:['>=9.4.0', '<10.0.0'], static:static_deps)
|
||||
|
||||
if not compiler.has_header_symbol('zim/zim.h', 'LIBZIM_WITH_XAPIAN', dependencies: libzim_dep)
|
||||
error('Libzim seems to be compiled without Xapian. Xapian support is mandatory.')
|
||||
endif
|
||||
|
||||
|
||||
extra_cflags = ''
|
||||
if host_machine.system() == 'windows' and static_deps
|
||||
if target_machine.system() == 'windows' and static_deps
|
||||
add_project_arguments('-DCURL_STATICLIB', language : 'cpp')
|
||||
extra_cflags += '-DCURL_STATICLIB'
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
add_project_arguments('-DNOMINMAX', language: 'cpp')
|
||||
extra_libs += ['-liphlpapi']
|
||||
|
||||
|
||||
ctpp2_include_path = ''
|
||||
has_ctpp2_dep = false
|
||||
ctpp2_prefix_install = get_option('ctpp2-install-prefix')
|
||||
ctpp2_link_args = []
|
||||
if ctpp2_prefix_install == ''
|
||||
if compiler.has_header('ctpp2/CTPP2Logger.hpp')
|
||||
if find_library_in_compiler
|
||||
ctpp2_lib = compiler.find_library('ctpp2')
|
||||
else
|
||||
ctpp2_lib = find_library('ctpp2')
|
||||
endif
|
||||
ctpp2_link_args = ['-lctpp2']
|
||||
if meson.is_cross_build() and host_machine.system() == 'windows'
|
||||
if find_library_in_compiler
|
||||
iconv_lib = compiler.find_library('iconv', required:false)
|
||||
else
|
||||
iconv_lib = find_library('iconv', required:false)
|
||||
endif
|
||||
if iconv_lib.found()
|
||||
ctpp2_link_args += ['-liconv']
|
||||
endif
|
||||
endif
|
||||
has_ctpp2_dep = true
|
||||
ctpp2_dep = declare_dependency(link_args:ctpp2_link_args)
|
||||
else
|
||||
message('ctpp2/CTPP2Logger.hpp not found. Compiling without CTPP2 support')
|
||||
endif
|
||||
else
|
||||
if not find_library_in_compiler
|
||||
error('For custom ctpp2_prefix_install you need a meson version >=0.31.0')
|
||||
endif
|
||||
ctpp2_include_path = ctpp2_prefix_install + '/include'
|
||||
ctpp2_include_args = ['-I'+ctpp2_include_path]
|
||||
if compiler.has_header('ctpp2/CTPP2Logger.hpp', args:ctpp2_include_args)
|
||||
ctpp2_include_dir = include_directories(ctpp2_include_path, is_system:true)
|
||||
ctpp2_lib_path = join_paths(ctpp2_prefix_install, get_option('libdir'))
|
||||
message(ctpp2_lib_path)
|
||||
ctpp2_lib = compiler.find_library('ctpp2', dirs:ctpp2_lib_path, required:false)
|
||||
if not ctpp2_lib.found()
|
||||
ctpp2_lib_path = join_paths(ctpp2_prefix_install, 'lib')
|
||||
message(ctpp2_lib_path)
|
||||
ctpp2_lib = compiler.find_library('ctpp2', dirs:ctpp2_lib_path)
|
||||
endif
|
||||
ctpp2_link_args = ['-L'+ctpp2_lib_path, '-lctpp2']
|
||||
if meson.is_cross_build() and host_machine.system() == 'windows'
|
||||
iconv_lib = compiler.find_library('iconv', required:false)
|
||||
if iconv_lib.found()
|
||||
ctpp2_link_args += ['-liconv']
|
||||
endif
|
||||
endif
|
||||
has_ctpp2_dep = true
|
||||
ctpp2_dep = declare_dependency(include_directories:ctpp2_include_dir, link_args:ctpp2_link_args)
|
||||
else
|
||||
message('ctpp2/CTPP2Logger.hpp not found. Compiling without CTPP2 support')
|
||||
endif
|
||||
endif
|
||||
|
||||
if build_machine.system() == 'windows'
|
||||
extra_libs += ['-lshlwapi', '-lwinmm']
|
||||
xapian_dep = dependency('xapian-core', required:false, static:static_deps)
|
||||
|
||||
all_deps = [thread_dep, libicu_dep, libzim_dep, xapian_dep, pugixml_dep, libcurl_dep]
|
||||
if has_ctpp2_dep
|
||||
all_deps += [ctpp2_dep]
|
||||
endif
|
||||
|
||||
|
||||
# Dependencies as string
|
||||
all_deps = [thread_dep, libzim_dep, pugixml_dep, libcurl_dep, microhttpd_dep, zlib_dep, xapian_dep]
|
||||
|
||||
# Dependencies as array
|
||||
all_deps += libicu_deps
|
||||
|
||||
inc = include_directories('include', extra_include)
|
||||
inc = include_directories('include')
|
||||
|
||||
conf = configuration_data()
|
||||
conf.set('LIBKIWIX_VERSION', '"@0@"'.format(meson.project_version()))
|
||||
conf.set('VERSION', '"@0@"'.format(meson.project_version()))
|
||||
conf.set('ENABLE_CTPP2', has_ctpp2_dep)
|
||||
|
||||
if build_machine.system() == 'windows'
|
||||
extra_link_args = ['-lshlwapi', '-lwinmm']
|
||||
else
|
||||
extra_link_args = []
|
||||
endif
|
||||
|
||||
subdir('include')
|
||||
subdir('scripts')
|
||||
subdir('static')
|
||||
subdir('src')
|
||||
subdir('test')
|
||||
if get_option('doc')
|
||||
subdir('docs')
|
||||
|
||||
pkg_requires = ['libzim', 'icu-i18n', 'pugixml', 'libcurl']
|
||||
if xapian_dep.found()
|
||||
pkg_requires += ['xapian-core']
|
||||
endif
|
||||
|
||||
pkg_mod = import('pkgconfig')
|
||||
pkg_mod.generate(libraries : [libkiwix] + extra_libs,
|
||||
version : meson.project_version(),
|
||||
name : 'libkiwix',
|
||||
filebase : 'libkiwix',
|
||||
description : 'A library that contains useful primitives that Kiwix readers have in common',
|
||||
extra_cflags: extra_cflags)
|
||||
if has_ctpp2_dep
|
||||
extra_libs += ctpp2_link_args
|
||||
if ctpp2_include_path != ''
|
||||
extra_cflags = ' -I'+ctpp2_include_path
|
||||
endif
|
||||
endif
|
||||
|
||||
pkg_conf = configuration_data()
|
||||
pkg_conf.set('prefix', get_option('prefix'))
|
||||
pkg_conf.set('requires', ' '.join(pkg_requires))
|
||||
pkg_conf.set('extra_libs', ' '.join(extra_libs))
|
||||
pkg_conf.set('extra_cflags', extra_cflags)
|
||||
pkg_conf.set('version', meson.project_version())
|
||||
configure_file(output : 'kiwix.pc',
|
||||
configuration : pkg_conf,
|
||||
input : 'kiwix.pc.in',
|
||||
install_dir: get_option('libdir')+'/pkgconfig'
|
||||
)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
option('static-linkage', type : 'boolean', value : false,
|
||||
description : 'Link statically with the dependencies.')
|
||||
option('doc', type : 'boolean', value : false,
|
||||
description : 'Build the documentations.')
|
||||
option('ctpp2-install-prefix', type : 'string', value : '',
|
||||
description : 'Prefix where ctpp libs has been installed')
|
||||
option('android', type : 'boolean', value : false,
|
||||
description : 'Do we make a kiwix-lib for android')
|
||||
|
||||
8
scripts/ctpp2c.sh
Executable file
8
scripts/ctpp2c.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
|
||||
ctpp2c=$1
|
||||
SOURCE=$(pwd)/$2
|
||||
DEST=$3
|
||||
|
||||
$ctpp2c $SOURCE $DEST
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
# Compute 'src' path
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
REPO_DIR=$(readlink -f "$SCRIPT_DIR"/..)
|
||||
DIRS="src include"
|
||||
|
||||
# Apply formating to all *.cpp and *.h files
|
||||
cd "$REPO_DIR"
|
||||
for FILE in $(find $DIRS -name '*.h' -o -name '*.cpp')
|
||||
do
|
||||
echo $FILE
|
||||
clang-format -i -style=file "$FILE"
|
||||
done
|
||||
@@ -1,148 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
'''
|
||||
Copyright 2022 Veloman Yunkan <veloman.yunkan@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301, USA.
|
||||
'''
|
||||
|
||||
import argparse
|
||||
import os.path
|
||||
import re
|
||||
import json
|
||||
|
||||
def to_identifier(name):
|
||||
ident = re.sub(r'[^0-9a-zA-Z]', '_', name)
|
||||
if ident[0].isnumeric():
|
||||
return "_"+ident
|
||||
return ident
|
||||
|
||||
def lang_code(filename):
|
||||
filename = os.path.basename(filename)
|
||||
lang = to_identifier(os.path.splitext(filename)[0])
|
||||
print(filename, '->', lang)
|
||||
return lang
|
||||
|
||||
from string import Template
|
||||
|
||||
def expand_cxx_template(t, **kwargs):
|
||||
return Template(t).substitute(**kwargs)
|
||||
|
||||
def cxx_string_literal(s):
|
||||
# Taking advantage of the fact the JSON string escape rules match
|
||||
# those of C++
|
||||
return 'u8' + json.dumps(s)
|
||||
|
||||
string_table_cxx_template = '''
|
||||
const I18nString $TABLE_NAME[] = {
|
||||
$TABLE_ENTRIES
|
||||
};
|
||||
'''
|
||||
|
||||
lang_table_entry_cxx_template = '''
|
||||
{
|
||||
$LANG_STRING_LITERAL,
|
||||
ARRAY_ELEMENT_COUNT($STRING_TABLE_NAME),
|
||||
$STRING_TABLE_NAME
|
||||
}'''
|
||||
|
||||
cxxfile_template = '''// This file is automatically generated. Do not modify it.
|
||||
|
||||
#include "server/i18n_utils.h"
|
||||
|
||||
namespace kiwix {
|
||||
namespace i18n {
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
$STRING_DATA
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
#define ARRAY_ELEMENT_COUNT(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
extern const I18nStringTable stringTables[] = {
|
||||
$LANG_TABLE
|
||||
};
|
||||
|
||||
extern const size_t langCount = $LANG_COUNT;
|
||||
|
||||
} // namespace i18n
|
||||
} // namespace kiwix
|
||||
'''
|
||||
|
||||
class Resource:
|
||||
def __init__(self, filename):
|
||||
filename = filename.strip()
|
||||
self.filename = filename
|
||||
self.lang_code = lang_code(filename)
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
self.data = f.read()
|
||||
|
||||
def get_string_table_name(self):
|
||||
return "string_table_for_" + self.lang_code
|
||||
|
||||
def get_string_table(self):
|
||||
table_entries = ",\n ".join(self.get_string_table_entries())
|
||||
return expand_cxx_template(string_table_cxx_template,
|
||||
TABLE_NAME=self.get_string_table_name(),
|
||||
TABLE_ENTRIES=table_entries)
|
||||
|
||||
def get_string_table_entries(self):
|
||||
d = json.loads(self.data)
|
||||
for k in sorted(d.keys()):
|
||||
if k != "@metadata":
|
||||
key_string = cxx_string_literal(k)
|
||||
value_string = cxx_string_literal(d[k])
|
||||
yield '{ ' + key_string + ', ' + value_string + ' }'
|
||||
|
||||
def get_lang_table_entry(self):
|
||||
return expand_cxx_template(lang_table_entry_cxx_template,
|
||||
LANG_STRING_LITERAL=cxx_string_literal(self.lang_code),
|
||||
STRING_TABLE_NAME=self.get_string_table_name())
|
||||
|
||||
|
||||
|
||||
def gen_c_file(resources):
|
||||
string_data = []
|
||||
lang_table = []
|
||||
for r in resources:
|
||||
string_data.append(r.get_string_table())
|
||||
lang_table.append(r.get_lang_table_entry())
|
||||
|
||||
return expand_cxx_template(cxxfile_template,
|
||||
STRING_DATA="\n".join(string_data),
|
||||
LANG_TABLE=",\n ".join(lang_table),
|
||||
LANG_COUNT=len(resources)
|
||||
)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--cxxfile',
|
||||
required=True,
|
||||
help='The Cpp file name to generate')
|
||||
parser.add_argument('i18n_resource_files', nargs='+',
|
||||
help='The list of resources to compile.')
|
||||
args = parser.parse_args()
|
||||
|
||||
resources = [Resource(filename) for filename in args.i18n_resource_files]
|
||||
|
||||
with open(args.cxxfile, 'w') as f:
|
||||
f.write(gen_c_file(resources))
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
.TH KIWIX-COMPILE-I18N "1" "January 2022" "Kiwix" "User Commands"
|
||||
.SH NAME
|
||||
kiwix-compile-i18n \- helper to compile Kiwix i18n (internationalization) data
|
||||
.SH SYNOPSIS
|
||||
\fBkiwix\-compile\-i18n\fR [\-h] \-\-cxxfile CXXFILE i18n_resource_files ...\fR
|
||||
.SH DESCRIPTION
|
||||
.TP
|
||||
i18n_resource_files ...
|
||||
The list of i18n resources to compile.
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
show a help message and exit
|
||||
.TP
|
||||
\fB\-\-cxxfile\fR CXXFILE
|
||||
The Cpp file name to generate
|
||||
.TP
|
||||
.SH AUTHOR
|
||||
Veloman Yunkan <veloman.yunkan@gmail.com>
|
||||
@@ -52,60 +52,26 @@ resource_getter_template = """
|
||||
return RESOURCE::{identifier};
|
||||
"""
|
||||
|
||||
resource_cacheid_getter_template = """
|
||||
if (name == "{common_name}")
|
||||
return "{cacheid}";
|
||||
"""
|
||||
|
||||
resource_decl_template = """{namespaces_open}
|
||||
extern const std::string {identifier};
|
||||
{namespaces_close}"""
|
||||
|
||||
BINARY_RESOURCE_EXTENSIONS = {'.ico', '.png', '.ttf'}
|
||||
|
||||
TEXT_RESOURCE_EXTENSIONS = {
|
||||
'.css',
|
||||
'.html',
|
||||
'.js',
|
||||
'.json',
|
||||
'.svg',
|
||||
'.tmpl',
|
||||
'.webmanifest',
|
||||
'.xml',
|
||||
}
|
||||
|
||||
if not BINARY_RESOURCE_EXTENSIONS.isdisjoint(TEXT_RESOURCE_EXTENSIONS):
|
||||
raise RuntimeError(f"The following file type extensions are declared to be both binary and text: {BINARY_RESOURCE_EXTENSIONS.intersection(TEXT_RESOURCE_EXTENSIONS)}")
|
||||
|
||||
def is_binary_resource(filename):
|
||||
_, extension = os.path.splitext(filename)
|
||||
is_binary = extension in BINARY_RESOURCE_EXTENSIONS
|
||||
is_text = extension in TEXT_RESOURCE_EXTENSIONS
|
||||
if not is_binary and not is_text:
|
||||
# all file type extensions of static resources must be listed
|
||||
# in either BINARY_RESOURCE_EXTENSIONS or TEXT_RESOURCE_EXTENSIONS
|
||||
raise RuntimeError(f"Unknown file type extension: {extension}")
|
||||
return is_binary
|
||||
|
||||
class Resource:
|
||||
def __init__(self, base_dirs, filename, cacheid=None):
|
||||
filename = filename
|
||||
def __init__(self, base_dirs, filename):
|
||||
filename = filename.strip()
|
||||
self.filename = filename
|
||||
self.identifier = full_identifier(filename)
|
||||
self.cacheid = cacheid
|
||||
found = False
|
||||
for base_dir in base_dirs:
|
||||
try:
|
||||
with open(os.path.join(base_dir, filename), 'rb') as f:
|
||||
self.data = f.read()
|
||||
if not is_binary_resource(filename):
|
||||
self.data = self.data.replace(b"\r\n", b"\n")
|
||||
found = True
|
||||
break
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
if not found:
|
||||
raise Exception("Resource not found: {}".format(filename))
|
||||
raise Exception("Impossible to found {}".format(filename))
|
||||
|
||||
def dump_impl(self):
|
||||
nb_row = len(self.data)//16 + (1 if len(self.data) % 16 else 0)
|
||||
@@ -115,34 +81,28 @@ class Resource:
|
||||
data_identifier="_".join([""]+self.identifier),
|
||||
resource_content=",\n ".join(", ".join("{:#04x}".format(i) for i in r) for r in sliced),
|
||||
resource_len=len(self.data),
|
||||
namespaces_open=" ".join("namespace {} {{".format(id) for id in self.identifier[:-1]),
|
||||
namespaces_open=" ".join("namespace {} {{".format(id) for id in self.identifier[:-1]),
|
||||
namespaces_close=" ".join(["}"]*(len(self.identifier)-1)),
|
||||
identifier=self.identifier[-1],
|
||||
env_identifier="RES_"+"_".join(self.identifier)+"_PATH"
|
||||
)
|
||||
|
||||
|
||||
def dump_getter(self):
|
||||
return resource_getter_template.format(
|
||||
common_name=self.filename,
|
||||
identifier="::".join(self.identifier)
|
||||
)
|
||||
|
||||
def dump_cacheid_getter(self):
|
||||
return resource_cacheid_getter_template.format(
|
||||
common_name=self.filename,
|
||||
cacheid=self.cacheid
|
||||
)
|
||||
|
||||
def dump_decl(self):
|
||||
return resource_decl_template.format(
|
||||
namespaces_open=" ".join("namespace {} {{".format(id) for id in self.identifier[:-1]),
|
||||
namespaces_open=" ".join("namespace {} {{".format(id) for id in self.identifier[:-1]),
|
||||
namespaces_close=" ".join(["}"]*(len(self.identifier)-1)),
|
||||
identifier=self.identifier[-1]
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
master_c_template = """//This file is automatically generated. Do not modify it.
|
||||
master_c_template = """//This file is automaically generated. Do not modify it.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <fstream>
|
||||
@@ -153,7 +113,7 @@ static std::string init_resource(const char* name, const unsigned char* content,
|
||||
char * resPath = getenv(name);
|
||||
if (NULL == resPath)
|
||||
return std::string(reinterpret_cast<const char*>(content), len);
|
||||
|
||||
|
||||
std::ifstream ifs(resPath);
|
||||
if (!ifs.good())
|
||||
return std::string(reinterpret_cast<const char*>(content), len);
|
||||
@@ -163,12 +123,7 @@ static std::string init_resource(const char* name, const unsigned char* content,
|
||||
|
||||
const std::string& getResource_{basename}(const std::string& name) {{
|
||||
{RESOURCES_GETTER}
|
||||
throw ResourceNotFound("Resource not found: " + name);
|
||||
}}
|
||||
|
||||
const char* getResourceCacheId_{basename}(const std::string& name) {{
|
||||
{RESOURCE_CACHEID_GETTER}
|
||||
return nullptr;
|
||||
throw ResourceNotFound("Resource not found.");
|
||||
}}
|
||||
|
||||
{RESOURCES}
|
||||
@@ -179,11 +134,10 @@ def gen_c_file(resources, basename):
|
||||
return master_c_template.format(
|
||||
RESOURCES="\n\n".join(r.dump_impl() for r in resources),
|
||||
RESOURCES_GETTER="\n\n".join(r.dump_getter() for r in resources),
|
||||
RESOURCE_CACHEID_GETTER="\n\n".join(r.dump_cacheid_getter() for r in resources if r.cacheid is not None),
|
||||
include_file=basename,
|
||||
basename=to_identifier(basename)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
master_h_template = """//This file is automaically generated. Do not modify it.
|
||||
@@ -205,10 +159,8 @@ class ResourceNotFound : public std::runtime_error {{
|
||||
}};
|
||||
|
||||
const std::string& getResource_{basename}(const std::string& name);
|
||||
const char* getResourceCacheId_{basename}(const std::string& name);
|
||||
|
||||
#define getResource(a) (getResource_{basename}(a))
|
||||
#define getResourceCacheId(a) (getResourceCacheId_{basename}(a))
|
||||
|
||||
#endif // KIWIX_{BASENAME}
|
||||
|
||||
@@ -230,17 +182,15 @@ if __name__ == "__main__":
|
||||
parser.add_argument('--source_dir',
|
||||
help="Additional directory where to look for resources.",
|
||||
action='append')
|
||||
parser.add_argument('resource_files', nargs='+',
|
||||
parser.add_argument('resource_file',
|
||||
help='The list of resources to compile.')
|
||||
args = parser.parse_args()
|
||||
|
||||
base_dir = os.path.dirname(os.path.realpath(args.resource_file))
|
||||
source_dir = args.source_dir or []
|
||||
resources = []
|
||||
for resfile in args.resource_files:
|
||||
base_dir = os.path.dirname(os.path.realpath(resfile))
|
||||
with open(resfile, 'r') as f:
|
||||
resources += [Resource([base_dir]+source_dir, *line.strip().split())
|
||||
for line in f.readlines()]
|
||||
with open(args.resource_file, 'r') as f:
|
||||
resources = [Resource([base_dir]+source_dir, filename)
|
||||
for filename in f.readlines()]
|
||||
|
||||
h_identifier = to_identifier(os.path.basename(args.hfile))
|
||||
with open(args.hfile, 'w') as f:
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
.TH KIWIX-COMPILE-RESOURCES "1" "August 2017" "Kiwix" "User Commands"
|
||||
.SH NAME
|
||||
kiwix-compile-resources \- helper to compile and generate some Kiwix resources
|
||||
.SH SYNOPSIS
|
||||
\fBkiwix\-compile\-resources\fR [\-h] [\-\-cxxfile CXXFILE] [\-\-hfile HFILE] resource_file ...\fR
|
||||
.SH DESCRIPTION
|
||||
.TP
|
||||
resource_file
|
||||
The list of resources to compile.
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
show a help message and exit
|
||||
.TP
|
||||
\fB\-\-cxxfile\fR CXXFILE
|
||||
The Cpp file name to generate
|
||||
.TP
|
||||
\fB\-\-hfile\fR HFILE
|
||||
The h file name to generate
|
||||
.SH AUTHOR
|
||||
Matthieu Gautier <mgautier@kymeria.fr>
|
||||
@@ -1,135 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
'''
|
||||
Copyright 2022 Veloman Yunkan <veloman.yunkan@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301, USA.
|
||||
'''
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import os.path
|
||||
import re
|
||||
|
||||
def read_resource_file(resource_file_path):
|
||||
with open(resource_file_path, 'r') as f:
|
||||
return [line.strip() for line in f]
|
||||
|
||||
def list_resources(resource_file_path):
|
||||
for resource_path in read_resource_file(resource_file_path):
|
||||
print(resource_path)
|
||||
|
||||
def compute_resource_revision(resource_path):
|
||||
with open(os.path.join(OUT_DIR, resource_path), 'rb') as f:
|
||||
return hashlib.sha1(f.read()).hexdigest()[:8]
|
||||
|
||||
resource_revisions = {}
|
||||
|
||||
def get_resource_revision(res):
|
||||
if not res in resource_revisions:
|
||||
preprocess_resource(res)
|
||||
resource_revisions[res] = compute_resource_revision(res)
|
||||
return resource_revisions[res]
|
||||
|
||||
RESOURCE_WITH_CACHEID_URL_PATTERN=r'(?P<pre>.*/(?P<resource>skin/[^"?]+)\?)KIWIXCACHEID(?P<post>[^"]*)'
|
||||
|
||||
def set_cacheid(resource_matchobj):
|
||||
pre = resource_matchobj.group('pre')
|
||||
resource = resource_matchobj.group('resource')
|
||||
post = resource_matchobj.group('post')
|
||||
cacheid = 'cacheid=' + get_resource_revision(resource)
|
||||
return pre + cacheid + post
|
||||
|
||||
def preprocess_text(s):
|
||||
if 'KIWIXCACHEID' in s:
|
||||
s = re.sub(RESOURCE_WITH_CACHEID_URL_PATTERN, set_cacheid, s)
|
||||
assert not 'KIWIXCACHEID' in s
|
||||
return s
|
||||
|
||||
def get_preprocessed_resource(srcpath):
|
||||
"""Get the transformed content of a resource
|
||||
|
||||
If the resource at srcpath is modified by preprocessing then this function
|
||||
returns the transformed content of the resource. Otherwise it returns None.
|
||||
"""
|
||||
try:
|
||||
with open(srcpath, 'r') as resource_file:
|
||||
content = resource_file.read()
|
||||
preprocessed_content = preprocess_text(content)
|
||||
return preprocessed_content if preprocessed_content != content else None
|
||||
except UnicodeDecodeError:
|
||||
# It was a binary resource
|
||||
return None
|
||||
|
||||
|
||||
def symlink_resource(src, resource_path):
|
||||
if os.path.exists(resource_path):
|
||||
if os.path.islink(resource_path) and os.readlink(resource_path) == src:
|
||||
return
|
||||
os.remove(resource_path)
|
||||
os.symlink(src, resource_path)
|
||||
|
||||
def preprocess_resource(resource_path):
|
||||
print('Preprocessing', resource_path, '...')
|
||||
resource_dir = os.path.dirname(resource_path)
|
||||
if resource_dir != '':
|
||||
os.makedirs(os.path.join(OUT_DIR, resource_dir), exist_ok=True)
|
||||
srcpath = os.path.join(BASE_DIR, resource_path)
|
||||
outpath = os.path.join(OUT_DIR, resource_path)
|
||||
if os.path.exists(outpath):
|
||||
os.remove(outpath)
|
||||
preprocessed_content = get_preprocessed_resource(srcpath)
|
||||
if preprocessed_content is None:
|
||||
symlink_resource(srcpath, outpath)
|
||||
else:
|
||||
with open(outpath, 'w') as target:
|
||||
print(preprocessed_content, end='', file=target)
|
||||
|
||||
|
||||
def copy_resource_list_file(src_path, dst_path):
|
||||
with open(src_path, 'r') as src:
|
||||
with open(dst_path, 'w') as dst:
|
||||
for line in src:
|
||||
res = line.strip()
|
||||
if line.startswith("skin/") and res in resource_revisions:
|
||||
dst.write(res + " " + resource_revisions[res] + "\n")
|
||||
else:
|
||||
dst.write(line)
|
||||
|
||||
def preprocess_resources(resource_file_path):
|
||||
resource_filename = os.path.basename(resource_file_path)
|
||||
for resource in read_resource_file(resource_file_path):
|
||||
if resource.startswith('skin/'):
|
||||
get_resource_revision(resource)
|
||||
else:
|
||||
preprocess_resource(resource)
|
||||
copy_resource_list_file(resource_file_path, os.path.join(OUT_DIR, resource_filename))
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
commands = parser.add_mutually_exclusive_group()
|
||||
commands.add_argument('--list-all', action='store_true')
|
||||
commands.add_argument('--preprocess', action='store_true')
|
||||
parser.add_argument('--outdir')
|
||||
parser.add_argument('resource_file')
|
||||
args = parser.parse_args()
|
||||
BASE_DIR = os.path.dirname(os.path.realpath(args.resource_file))
|
||||
OUT_DIR = args.outdir
|
||||
|
||||
if args.list_all:
|
||||
list_resources(args.resource_file)
|
||||
elif args.preprocess:
|
||||
preprocess_resources(args.resource_file)
|
||||
@@ -1,13 +1,5 @@
|
||||
|
||||
res_manager = find_program('kiwix-resources')
|
||||
res_compiler = find_program('kiwix-compile-resources')
|
||||
intermediate_ctpp2c = find_program('ctpp2c.sh')
|
||||
|
||||
install_data(res_compiler.path(), install_dir:get_option('bindir'))
|
||||
|
||||
install_man('kiwix-compile-resources.1')
|
||||
|
||||
i18n_compiler = find_program('kiwix-compile-i18n')
|
||||
|
||||
install_data(i18n_compiler.path(), install_dir:get_option('bindir'))
|
||||
|
||||
install_man('kiwix-compile-i18n.1')
|
||||
|
||||
13
src/android/AndroidManifest.xml
Normal file
13
src/android/AndroidManifest.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
package="kiwix.org.kiwixlib"
|
||||
>
|
||||
|
||||
<application android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright 2011 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
* Copyright (C) 2013 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
* Copyright (C) 2017 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,21 +18,27 @@
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_PATHTOOLS_H
|
||||
#define KIWIX_PATHTOOLS_H
|
||||
#include <jni.h>
|
||||
#include "org_kiwix_kiwixlib_JNIKiwix.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string WideToUtf8(const std::wstring& wstr);
|
||||
std::wstring Utf8ToWide(const std::string& str);
|
||||
#endif
|
||||
#include "unicode/putil.h"
|
||||
|
||||
unsigned int getFileSize(const std::string& path);
|
||||
std::string getFileSizeAsString(const std::string& path);
|
||||
std::string makeTmpDirectory();
|
||||
bool copyFile(const std::string& sourcePath, const std::string& destPath);
|
||||
bool writeTextFile(const std::string& path, const std::string& content);
|
||||
#include "utils.h"
|
||||
|
||||
#endif
|
||||
pthread_mutex_t globalLock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_kiwix_kiwixlib_JNIKiwix_setDataDirectory(
|
||||
JNIEnv* env, jobject obj, jstring dirStr)
|
||||
{
|
||||
std::string cPath = jni2c(dirStr, env);
|
||||
|
||||
Lock l;
|
||||
try {
|
||||
u_setDataDirectory(cPath.c_str());
|
||||
} catch (...) {
|
||||
std::cerr << "Unable to set data directory " << cPath << std::endl;
|
||||
}
|
||||
}
|
||||
424
src/android/kiwixreader.cpp
Normal file
424
src/android/kiwixreader.cpp
Normal file
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
* Copyright (C) 2017 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <jni.h>
|
||||
#include <zim/file.h>
|
||||
#include <android/log.h>
|
||||
#include "org_kiwix_kiwixlib_JNIKiwixReader.h"
|
||||
|
||||
#include "common/base64.h"
|
||||
#include "reader.h"
|
||||
#include "utils.h"
|
||||
|
||||
/* Kiwix Reader JNI functions */
|
||||
JNIEXPORT jlong JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getNativeReader(
|
||||
JNIEnv* env, jobject obj, jstring filename)
|
||||
{
|
||||
std::string cPath = jni2c(filename, env);
|
||||
|
||||
__android_log_print(ANDROID_LOG_INFO, "kiwix", "Attempting to create reader with: %s", cPath.c_str());
|
||||
Lock l;
|
||||
try {
|
||||
kiwix::Reader* reader = new kiwix::Reader(cPath);
|
||||
return reinterpret_cast<jlong>(new Handle<kiwix::Reader>(reader));
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_WARN, "kiwix", "Error opening ZIM file");
|
||||
__android_log_print(ANDROID_LOG_WARN, "kiwix", e.what());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_dispose(JNIEnv* env, jobject obj)
|
||||
{
|
||||
Handle<kiwix::Reader>::dispose(env, obj);
|
||||
}
|
||||
|
||||
#define READER (Handle<kiwix::Reader>::getHandle(env, obj))
|
||||
|
||||
/* Kiwix library functions */
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_getMainPage(JNIEnv* env, jobject obj)
|
||||
{
|
||||
jstring url;
|
||||
|
||||
try {
|
||||
std::string cUrl = READER->getMainPage().getPath();
|
||||
url = c2jni(cUrl, env);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM main page");
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
url = NULL;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_getId(JNIEnv* env, jobject obj)
|
||||
{
|
||||
jstring id;
|
||||
|
||||
try {
|
||||
std::string cId = READER->getId();
|
||||
id = c2jni(cId, env);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM id");
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
id = NULL;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_getFileSize(JNIEnv* env, jobject obj)
|
||||
{
|
||||
jint size;
|
||||
|
||||
try {
|
||||
int cSize = READER->getFileSize();
|
||||
size = c2jni(cSize);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM file size");
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_getCreator(JNIEnv* env, jobject obj)
|
||||
{
|
||||
jstring creator;
|
||||
|
||||
try {
|
||||
std::string cCreator = READER->getCreator();
|
||||
creator = c2jni(cCreator, env);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM creator");
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
creator = NULL;
|
||||
}
|
||||
|
||||
return creator;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_getPublisher(JNIEnv* env, jobject obj)
|
||||
{
|
||||
jstring publisher;
|
||||
|
||||
try {
|
||||
std::string cPublisher = READER->getPublisher();
|
||||
publisher = c2jni(cPublisher, env);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM publish");
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
publisher = NULL;
|
||||
}
|
||||
return publisher;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_getName(JNIEnv* env, jobject obj)
|
||||
{
|
||||
jstring name;
|
||||
|
||||
try {
|
||||
std::string cName = READER->getName();
|
||||
name = c2jni(cName, env);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM name");
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
name = NULL;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_getFavicon(JNIEnv* env, jobject obj)
|
||||
{
|
||||
jstring favicon;
|
||||
|
||||
try {
|
||||
std::string cContent;
|
||||
std::string cMime;
|
||||
READER->getFavicon(cContent, cMime);
|
||||
favicon = c2jni(
|
||||
base64_encode(cContent),
|
||||
env);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM favicon");
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
favicon = NULL;
|
||||
}
|
||||
return favicon;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_getDate(JNIEnv* env, jobject obj)
|
||||
{
|
||||
jstring date;
|
||||
|
||||
try {
|
||||
std::string cDate = READER->getDate();
|
||||
date = c2jni(cDate, env);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM date");
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
date = NULL;
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_getLanguage(JNIEnv* env, jobject obj)
|
||||
{
|
||||
jstring language;
|
||||
|
||||
try {
|
||||
std::string cLanguage = READER->getLanguage();
|
||||
language = c2jni(cLanguage, env);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get ZIM language");
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
language = NULL;
|
||||
}
|
||||
|
||||
return language;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getMimeType(
|
||||
JNIEnv* env, jobject obj, jstring url)
|
||||
{
|
||||
jstring mimeType;
|
||||
|
||||
std::string cUrl = jni2c(url, env);
|
||||
try {
|
||||
auto entry = READER->getEntryFromEncodedPath(cUrl);
|
||||
auto cMimeType = entry.getMimetype();
|
||||
mimeType = c2jni(cMimeType, env);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get mime-type for url: %s", cUrl.c_str());
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
mimeType = NULL;
|
||||
}
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getContent(
|
||||
JNIEnv* env, jobject obj, jstring url, jobject titleObj, jobject mimeTypeObj, jobject sizeObj)
|
||||
{
|
||||
/* Default values */
|
||||
setStringObjValue("", titleObj, env);
|
||||
setStringObjValue("", mimeTypeObj, env);
|
||||
setIntObjValue(0, sizeObj, env);
|
||||
jbyteArray data = env->NewByteArray(0);
|
||||
|
||||
/* Retrieve the content */
|
||||
std::string cUrl = jni2c(url, env);
|
||||
unsigned int cSize = 0;
|
||||
|
||||
try {
|
||||
auto entry = READER->getEntryFromEncodedPath(cUrl);
|
||||
entry = entry.getFinalEntry();
|
||||
cSize = entry.getSize();
|
||||
setIntObjValue(cSize, sizeObj, env);
|
||||
|
||||
data = env->NewByteArray(cSize);
|
||||
env->SetByteArrayRegion(
|
||||
data, 0, cSize, reinterpret_cast<const jbyte*>(entry.getBlob().data()));
|
||||
|
||||
setStringObjValue(entry.getMimetype(), mimeTypeObj, env);
|
||||
setStringObjValue(entry.getTitle(), titleObj, env);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get content for url: %s", cUrl.c_str());
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getContentPart(
|
||||
JNIEnv* env, jobject obj, jstring url, jint offset, jint len, jobject sizeObj)
|
||||
{
|
||||
jbyteArray data = env->NewByteArray(0);
|
||||
setIntObjValue(0, sizeObj, env);
|
||||
|
||||
/* Default values */
|
||||
/* Retrieve the content */
|
||||
std::string cUrl = jni2c(url, env);
|
||||
unsigned int cOffset = jni2c(offset);
|
||||
unsigned int cLen = jni2c(len);
|
||||
try {
|
||||
auto entry = READER->getEntryFromEncodedPath(cUrl);
|
||||
entry = entry.getFinalEntry();
|
||||
|
||||
if (cLen == 0) {
|
||||
setIntObjValue(entry.getSize(), sizeObj, env);
|
||||
} else if (cOffset+cLen < entry.getSize()) {
|
||||
auto blob = entry.getBlob(cOffset, cLen);
|
||||
data = env->NewByteArray(cLen);
|
||||
env->SetByteArrayRegion(
|
||||
data, 0, cLen, reinterpret_cast<const jbyte*>(blob.data()));
|
||||
setIntObjValue(cLen, sizeObj, env);
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get partial content for url: %s (%u : %u)", cUrl.c_str(), cOffset, cLen);
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_getDirectAccessInformation(
|
||||
JNIEnv* env, jobject obj, jstring url)
|
||||
{
|
||||
jclass classPair = env->FindClass("org/kiwix/kiwixlib/Pair");
|
||||
jmethodID midPairinit = env->GetMethodID(classPair, "<init>", "()V");
|
||||
jobject pair = env->NewObject(classPair, midPairinit);
|
||||
setPairObjValue("", 0, pair, env);
|
||||
|
||||
std::string cUrl = jni2c(url, env);
|
||||
try {
|
||||
auto entry = READER->getEntryFromEncodedPath(cUrl);
|
||||
entry = entry.getFinalEntry();
|
||||
auto part_info = entry.getDirectAccessInfo();
|
||||
setPairObjValue(part_info.first, part_info.second, pair, env);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get direct access info for url: %s", cUrl.c_str());
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
}
|
||||
return pair;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_searchSuggestions(JNIEnv* env,
|
||||
jobject obj,
|
||||
jstring prefix,
|
||||
jint count)
|
||||
{
|
||||
jboolean retVal = JNI_FALSE;
|
||||
std::string cPrefix = jni2c(prefix, env);
|
||||
unsigned int cCount = jni2c(count);
|
||||
|
||||
try {
|
||||
if (READER->searchSuggestionsSmart(cPrefix, cCount)) {
|
||||
retVal = JNI_TRUE;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_WARN, "kiwix", "Unable to get search results for pattern: %s", cPrefix.c_str());
|
||||
__android_log_print(ANDROID_LOG_WARN, "kiwix", e.what());
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_getNextSuggestion(JNIEnv* env,
|
||||
jobject obj,
|
||||
jobject titleObj)
|
||||
{
|
||||
jboolean retVal = JNI_FALSE;
|
||||
std::string cTitle;
|
||||
|
||||
try {
|
||||
if (READER->getNextSuggestion(cTitle)) {
|
||||
setStringObjValue(cTitle, titleObj, env);
|
||||
retVal = JNI_TRUE;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_WARN, "kiwix", "Unable to get next suggestion");
|
||||
__android_log_print(ANDROID_LOG_WARN, "kiwix", e.what());
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_getPageUrlFromTitle(JNIEnv* env,
|
||||
jobject obj,
|
||||
jstring title,
|
||||
jobject urlObj)
|
||||
{
|
||||
std::string cTitle = jni2c(title, env);
|
||||
|
||||
try {
|
||||
auto entry = READER->getEntryFromTitle(cTitle);
|
||||
entry = entry.getFinalEntry();
|
||||
setStringObjValue(entry.getPath(), urlObj, env);
|
||||
return JNI_TRUE;
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_WARN, "kiwix", "Unable to get url for title %s: ", cTitle.c_str());
|
||||
__android_log_print(ANDROID_LOG_WARN, "kiwix", e.what());
|
||||
}
|
||||
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getTitle(
|
||||
JNIEnv* env, jobject obj)
|
||||
{
|
||||
jstring title;
|
||||
|
||||
try {
|
||||
std::string cTitle = READER->getTitle();
|
||||
title = c2jni(cTitle, env);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get zim title");
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
title = NULL;
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixReader_getDescription(JNIEnv* env, jobject obj)
|
||||
{
|
||||
jstring description;
|
||||
|
||||
try {
|
||||
std::string cDescription = READER->getDescription();
|
||||
description = c2jni(cDescription, env);
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get zim description");
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
description = NULL;
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_org_kiwix_kiwixlib_JNIKiwixReader_getRandomPage(
|
||||
JNIEnv* env, jobject obj, jobject urlObj)
|
||||
{
|
||||
jboolean retVal = JNI_FALSE;
|
||||
std::string cUrl;
|
||||
|
||||
try {
|
||||
std::string cUrl = READER->getRandomPage().getPath();
|
||||
setStringObjValue(cUrl, urlObj, env);
|
||||
retVal = JNI_TRUE;
|
||||
} catch (std::exception& e) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", "Unable to get random page");
|
||||
__android_log_print(ANDROID_LOG_ERROR, "kiwix", e.what());
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
124
src/android/kiwixsearcher.cpp
Normal file
124
src/android/kiwixsearcher.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
* Copyright (C) 2017 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <zim/file.h>
|
||||
#include "org_kiwix_kiwixlib_JNIKiwixSearcher.h"
|
||||
#include "org_kiwix_kiwixlib_JNIKiwixSearcher_Result.h"
|
||||
|
||||
#include "reader.h"
|
||||
#include "searcher.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define SEARCHER (Handle<kiwix::Searcher>::getHandle(env, obj))
|
||||
#define RESULT (Handle<kiwix::Result>::getHandle(env, obj))
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixSearcher_dispose(JNIEnv* env, jobject obj)
|
||||
{
|
||||
Handle<kiwix::Searcher>::dispose(env, obj);
|
||||
}
|
||||
|
||||
/* Kiwix Reader JNI functions */
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixSearcher_getNativeHandle(JNIEnv* env,
|
||||
jobject obj)
|
||||
{
|
||||
kiwix::Searcher* searcher = new kiwix::Searcher();
|
||||
return reinterpret_cast<jlong>(new Handle<kiwix::Searcher>(searcher));
|
||||
}
|
||||
|
||||
/* Kiwix library functions */
|
||||
JNIEXPORT void JNICALL Java_org_kiwix_kiwixlib_JNIKiwixSearcher_addReader(
|
||||
JNIEnv* env, jobject obj, jobject reader)
|
||||
{
|
||||
auto searcher = SEARCHER;
|
||||
|
||||
searcher->add_reader(*(Handle<kiwix::Reader>::getHandle(env, reader)), "");
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_kiwix_kiwixlib_JNIKiwixSearcher_search(
|
||||
JNIEnv* env, jobject obj, jstring query, jint count)
|
||||
{
|
||||
std::string cquery = jni2c(query, env);
|
||||
unsigned int ccount = jni2c(count);
|
||||
|
||||
SEARCHER->search(cquery, 0, ccount);
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixSearcher_getNextResult(JNIEnv* env,
|
||||
jobject obj)
|
||||
{
|
||||
jobject result = nullptr;
|
||||
|
||||
kiwix::Result* cresult = SEARCHER->getNextResult();
|
||||
if (cresult != nullptr) {
|
||||
jclass resultclass
|
||||
= env->FindClass("org/kiwix/kiwixlib/JNIKiwixSearcher$Result");
|
||||
jmethodID ctor = env->GetMethodID(
|
||||
resultclass, "<init>", "(Lorg/kiwix/kiwixlib/JNIKiwixSearcher;JLorg/kiwix/kiwixlib/JNIKiwixSearcher;)V");
|
||||
result = env->NewObject(resultclass, ctor, obj, reinterpret_cast<jlong>(new Handle<kiwix::Result>(cresult)), obj);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_kiwix_kiwixlib_JNIKiwixSearcher_00024Result_dispose(
|
||||
JNIEnv* env, jobject obj)
|
||||
{
|
||||
Handle<kiwix::Result>::dispose(env, obj);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixSearcher_00024Result_getUrl(JNIEnv* env,
|
||||
jobject obj)
|
||||
{
|
||||
try {
|
||||
return c2jni(RESULT->get_url(), env);
|
||||
} catch (...) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixSearcher_00024Result_getTitle(JNIEnv* env,
|
||||
jobject obj)
|
||||
{
|
||||
try {
|
||||
return c2jni(RESULT->get_title(), env);
|
||||
} catch (...) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixSearcher_00024Result_getSnippet(JNIEnv* env,
|
||||
jobject obj)
|
||||
{
|
||||
return c2jni(RESULT->get_snippet(), env);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_kiwix_kiwixlib_JNIKiwixSearcher_00024Result_getContent(JNIEnv* env,
|
||||
jobject obj)
|
||||
{
|
||||
return c2jni(RESULT->get_content(), env);
|
||||
}
|
||||
26
src/android/meson.build
Normal file
26
src/android/meson.build
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
kiwix_jni = custom_target('jni',
|
||||
input: ['org/kiwix/kiwixlib/JNIKiwix.java',
|
||||
'org/kiwix/kiwixlib/JNIKiwixReader.java',
|
||||
'org/kiwix/kiwixlib/JNIKiwixSearcher.java',
|
||||
'org/kiwix/kiwixlib/JNIKiwixInt.java',
|
||||
'org/kiwix/kiwixlib/JNIKiwixString.java',
|
||||
'org/kiwix/kiwixlib/JNIKiwixBool.java',
|
||||
'org/kiwix/kiwixlib/JNIKiwixException.java',
|
||||
'org/kiwix/kiwixlib/Pair.java'],
|
||||
output: ['org_kiwix_kiwixlib_JNIKiwix.h',
|
||||
'org_kiwix_kiwixlib_JNIKiwixReader.h',
|
||||
'org_kiwix_kiwixlib_JNIKiwixSearcher.h',
|
||||
'org_kiwix_kiwixlib_JNIKiwixSearcher_Result.h'],
|
||||
command:['javac', '-d', '@OUTDIR@', '-h', '@OUTDIR@', '@INPUT@']
|
||||
)
|
||||
|
||||
kiwix_sources += [
|
||||
'android/kiwix.cpp',
|
||||
'android/kiwixreader.cpp',
|
||||
'android/kiwixsearcher.cpp',
|
||||
kiwix_jni]
|
||||
|
||||
install_subdir('org', install_dir: 'kiwix-lib/java')
|
||||
install_subdir('res', install_dir: 'kiwix-lib')
|
||||
install_data('AndroidManifest.xml', install_dir: 'kiwix-lib')
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright 2023 Nikhil Tanwar <2002nikhiltanwar@gmail.com>
|
||||
* Copyright (C) 2013 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
* Copyright (C) 2017 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,34 +18,14 @@
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_HTML_DUMPER_H
|
||||
#define KIWIX_HTML_DUMPER_H
|
||||
package org.kiwix.kiwixlib;
|
||||
|
||||
#include <string>
|
||||
import org.kiwix.kiwixlib.JNIKiwixReader;
|
||||
import org.kiwix.kiwixlib.JNIKiwixString;
|
||||
|
||||
#include "library_dumper.h"
|
||||
|
||||
namespace kiwix
|
||||
public class JNIKiwix
|
||||
{
|
||||
static { System.loadLibrary("kiwix"); }
|
||||
|
||||
/**
|
||||
* A class to dump Library in HTML format.
|
||||
*/
|
||||
class HTMLDumper : public LibraryDumper
|
||||
{
|
||||
public:
|
||||
HTMLDumper(const Library* library, const NameMapper* NameMapper);
|
||||
~HTMLDumper();
|
||||
|
||||
|
||||
/**
|
||||
* Dump library in HTML
|
||||
*
|
||||
* @return HTML content
|
||||
*/
|
||||
std::string dumpPlainHTML(kiwix::Filter filter) const;
|
||||
};
|
||||
|
||||
public native void setDataDirectory(String icuDataDir);
|
||||
}
|
||||
|
||||
#endif // KIWIX_HTML_DUMPER_H
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021 Veloman Yunkan <veloman.yunkan@gmail.com>
|
||||
* Copyright (C) 2013 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,17 +17,9 @@
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_OPDS_CATALOG_H
|
||||
#define KIWIX_OPDS_CATALOG_H
|
||||
package org.kiwix.kiwixlib;
|
||||
|
||||
|
||||
#include "library.h"
|
||||
|
||||
namespace kiwix
|
||||
public class JNIKiwixBool
|
||||
{
|
||||
|
||||
std::string getSearchUrl(const Filter& f);
|
||||
|
||||
} // namespace kiwix
|
||||
|
||||
#endif // KIWIX_OPDS_CATALOG_H
|
||||
public boolean value;
|
||||
}
|
||||
27
src/android/org/kiwix/kiwixlib/JNIKiwixException.java
Normal file
27
src/android/org/kiwix/kiwixlib/JNIKiwixException.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Matthieu Gautier <mgautier@kymeria.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixlib;
|
||||
|
||||
public class JNIKiwixException extends Exception
|
||||
{
|
||||
public JNIKiwixException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
* Copyright (C) 2013 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,8 +17,9 @@
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <microhttpd.h>
|
||||
package org.kiwix.kiwixlib;
|
||||
|
||||
#if MHD_VERSION < 0x00097002
|
||||
typedef int MHD_Result;
|
||||
#endif
|
||||
public class JNIKiwixInt
|
||||
{
|
||||
public int value;
|
||||
}
|
||||
127
src/android/org/kiwix/kiwixlib/JNIKiwixReader.java
Normal file
127
src/android/org/kiwix/kiwixlib/JNIKiwixReader.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
* Copyright (C) 2017 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixlib;
|
||||
|
||||
import org.kiwix.kiwixlib.JNIKiwixException;
|
||||
import org.kiwix.kiwixlib.JNIKiwixString;
|
||||
import org.kiwix.kiwixlib.JNIKiwixInt;
|
||||
import org.kiwix.kiwixlib.JNIKiwixSearcher;
|
||||
import org.kiwix.kiwixlib.Pair;
|
||||
|
||||
public class JNIKiwixReader
|
||||
{
|
||||
public native String getMainPage();
|
||||
|
||||
public native String getTitle();
|
||||
|
||||
public native String getId();
|
||||
|
||||
public native String getLanguage();
|
||||
|
||||
public native String getMimeType(String url);
|
||||
|
||||
public native byte[] getContent(String url,
|
||||
JNIKiwixString title,
|
||||
JNIKiwixString mimeType,
|
||||
JNIKiwixInt size);
|
||||
|
||||
/**
|
||||
* getContentPart.
|
||||
*
|
||||
* Get only a part of the content of the article.
|
||||
* Return a byte array of `len` size starting from offset `offset`.
|
||||
* Set `size` to the number of bytes read
|
||||
* (`len` if everything is ok, 0 in case of error).
|
||||
* If `len` == 0, no bytes are read but `size` is set to the total size of the
|
||||
* article.
|
||||
*/
|
||||
public native byte[] getContentPart(String url,
|
||||
int offest,
|
||||
int len,
|
||||
JNIKiwixInt size);
|
||||
|
||||
/**
|
||||
* getDirectAccessInformation.
|
||||
*
|
||||
* Return information giving where the content is located in the zim file.
|
||||
*
|
||||
* Some contents (binary content) are stored uncompressed in the zim file.
|
||||
* Knowing this information, it could be interesting to directly open
|
||||
* the zim file (or zim part) and directly read the content from it (and so
|
||||
* bypassing the libzim).
|
||||
*
|
||||
* Return a `Pair` (filename, offset) where the content is located.
|
||||
*
|
||||
* If the content cannot be directly accessed (content is compressed or zim
|
||||
* file is cut in the middle of the content), the filename is an empty string
|
||||
* and offset is zero.
|
||||
*/
|
||||
public native Pair getDirectAccessInformation(String url);
|
||||
|
||||
public native boolean searchSuggestions(String prefix, int count);
|
||||
|
||||
public native boolean getNextSuggestion(JNIKiwixString title);
|
||||
|
||||
public native boolean getPageUrlFromTitle(String title, JNIKiwixString url);
|
||||
|
||||
public native String getDescription();
|
||||
|
||||
public native String getDate();
|
||||
|
||||
public native String getFavicon();
|
||||
|
||||
public native String getCreator();
|
||||
|
||||
public native String getPublisher();
|
||||
|
||||
public native String getName();
|
||||
|
||||
public native int getFileSize();
|
||||
|
||||
public native int getArticleCount();
|
||||
|
||||
public native int getMediaCount();
|
||||
|
||||
public native boolean getRandomPage(JNIKiwixString url);
|
||||
|
||||
public JNIKiwixSearcher search(String query, int count)
|
||||
{
|
||||
JNIKiwixSearcher searcher = new JNIKiwixSearcher();
|
||||
searcher.addKiwixReader(this);
|
||||
searcher.search(query, count);
|
||||
return searcher;
|
||||
}
|
||||
|
||||
public JNIKiwixReader(String filename) throws JNIKiwixException
|
||||
{
|
||||
nativeHandle = getNativeReader(filename);
|
||||
if (nativeHandle == 0) {
|
||||
throw new JNIKiwixException("Cannot open zimfile "+filename);
|
||||
}
|
||||
}
|
||||
public JNIKiwixReader() {
|
||||
|
||||
}
|
||||
public native void dispose();
|
||||
|
||||
private native long getNativeReader(String filename);
|
||||
private long nativeHandle;
|
||||
}
|
||||
67
src/android/org/kiwix/kiwixlib/JNIKiwixSearcher.java
Normal file
67
src/android/org/kiwix/kiwixlib/JNIKiwixSearcher.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
* Copyright (C) 2017 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
package org.kiwix.kiwixlib;
|
||||
|
||||
import org.kiwix.kiwixlib.JNIKiwixReader;
|
||||
import java.util.Vector;
|
||||
|
||||
public class JNIKiwixSearcher
|
||||
{
|
||||
public class Result
|
||||
{
|
||||
private long nativeHandle;
|
||||
private JNIKiwixSearcher searcher;
|
||||
public Result(long handle, JNIKiwixSearcher _searcher)
|
||||
{
|
||||
nativeHandle = handle;
|
||||
searcher = _searcher;
|
||||
}
|
||||
public native String getUrl();
|
||||
public native String getTitle();
|
||||
public native String getContent();
|
||||
public native String getSnippet();
|
||||
public native void dispose();
|
||||
}
|
||||
|
||||
public JNIKiwixSearcher()
|
||||
{
|
||||
nativeHandle = getNativeHandle();
|
||||
usedReaders = new Vector();
|
||||
}
|
||||
public native void dispose();
|
||||
|
||||
private native long getNativeHandle();
|
||||
private long nativeHandle;
|
||||
private Vector usedReaders;
|
||||
|
||||
public native void addReader(JNIKiwixReader reader);
|
||||
public void addKiwixReader(JNIKiwixReader reader)
|
||||
{
|
||||
addReader(reader);
|
||||
usedReaders.addElement(reader);
|
||||
};
|
||||
|
||||
public native void search(String query, int count);
|
||||
|
||||
public native Result getNextResult();
|
||||
public native boolean hasMoreResult();
|
||||
}
|
||||
25
src/android/org/kiwix/kiwixlib/JNIKiwixString.java
Normal file
25
src/android/org/kiwix/kiwixlib/JNIKiwixString.java
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixlib;
|
||||
|
||||
public class JNIKiwixString
|
||||
{
|
||||
public String value;
|
||||
}
|
||||
26
src/android/org/kiwix/kiwixlib/Pair.java
Normal file
26
src/android/org/kiwix/kiwixlib/Pair.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixlib;
|
||||
|
||||
public class Pair
|
||||
{
|
||||
public String filename;
|
||||
public int offset;
|
||||
}
|
||||
3
src/android/res/values/strings.xml
Normal file
3
src/android/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Kiwix Lib</string>
|
||||
</resources>
|
||||
150
src/android/utils.h
Normal file
150
src/android/utils.h
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
* Copyright (C) 2017 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _ANDROID_JNI_UTILS_H
|
||||
#define _ANDROID_JNI_UTILS_H
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string>
|
||||
|
||||
extern pthread_mutex_t globalLock;
|
||||
|
||||
inline jfieldID getHandleField(JNIEnv* env, jobject obj)
|
||||
{
|
||||
jclass c = env->GetObjectClass(obj);
|
||||
// J is the type signature for long:
|
||||
return env->GetFieldID(c, "nativeHandle", "J");
|
||||
}
|
||||
|
||||
class Lock
|
||||
{
|
||||
protected:
|
||||
pthread_mutex_t* lock;
|
||||
|
||||
public:
|
||||
Lock() : lock(&globalLock) { pthread_mutex_lock(lock); }
|
||||
Lock(const Lock&) = delete;
|
||||
Lock& operator=(const Lock&) = delete;
|
||||
Lock(Lock&& other) : lock(&globalLock) { other.lock = nullptr; }
|
||||
virtual ~Lock()
|
||||
{
|
||||
if (lock) {
|
||||
pthread_mutex_unlock(lock);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class LockedHandle;
|
||||
|
||||
template <class T>
|
||||
class Handle
|
||||
{
|
||||
protected:
|
||||
T* h;
|
||||
|
||||
public:
|
||||
Handle(T* h) : h(h){};
|
||||
|
||||
// No destructor. This must and will be handled by dispose method.
|
||||
|
||||
static LockedHandle<T> getHandle(JNIEnv* env, jobject obj)
|
||||
{
|
||||
jlong handle = env->GetLongField(obj, getHandleField(env, obj));
|
||||
return LockedHandle<T>(reinterpret_cast<Handle<T>*>(handle));
|
||||
}
|
||||
|
||||
static void dispose(JNIEnv* env, jobject obj)
|
||||
{
|
||||
auto lHandle = getHandle(env, obj);
|
||||
auto handle = lHandle.h;
|
||||
delete handle->h;
|
||||
delete handle;
|
||||
}
|
||||
friend class LockedHandle<T>;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct LockedHandle : public Lock {
|
||||
Handle<T>* h;
|
||||
LockedHandle(Handle<T>* h) : h(h) {}
|
||||
T* operator->() { return h->h; }
|
||||
T* operator*() { return h->h; }
|
||||
operator bool() const { return (h->h != nullptr); }
|
||||
};
|
||||
|
||||
/* c2jni type conversion functions */
|
||||
inline jboolean c2jni(const bool& val) { return val ? JNI_TRUE : JNI_FALSE; }
|
||||
inline jstring c2jni(const std::string& val, JNIEnv* env)
|
||||
{
|
||||
return env->NewStringUTF(val.c_str());
|
||||
}
|
||||
|
||||
inline jint c2jni(const int val) { return (jint)val; }
|
||||
inline jint c2jni(const unsigned val) { return (unsigned)val; }
|
||||
/* jni2c type conversion functions */
|
||||
inline bool jni2c(const jboolean& val) { return val == JNI_TRUE; }
|
||||
inline std::string jni2c(const jstring& val, JNIEnv* env)
|
||||
{
|
||||
const char* chars = env->GetStringUTFChars(val, 0);
|
||||
std::string ret(chars);
|
||||
env->ReleaseStringUTFChars(val, chars);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline int jni2c(const jint val) { return (int)val; }
|
||||
/* Method to deal with variable passed by reference */
|
||||
inline void setStringObjValue(const std::string& value,
|
||||
const jobject obj,
|
||||
JNIEnv* env)
|
||||
{
|
||||
jclass objClass = env->GetObjectClass(obj);
|
||||
jfieldID objFid = env->GetFieldID(objClass, "value", "Ljava/lang/String;");
|
||||
env->SetObjectField(obj, objFid, c2jni(value, env));
|
||||
}
|
||||
|
||||
inline void setIntObjValue(const int value, const jobject obj, JNIEnv* env)
|
||||
{
|
||||
jclass objClass = env->GetObjectClass(obj);
|
||||
jfieldID objFid = env->GetFieldID(objClass, "value", "I");
|
||||
env->SetIntField(obj, objFid, value);
|
||||
}
|
||||
|
||||
inline void setBoolObjValue(const bool value, const jobject obj, JNIEnv* env)
|
||||
{
|
||||
jclass objClass = env->GetObjectClass(obj);
|
||||
jfieldID objFid = env->GetFieldID(objClass, "value", "Z");
|
||||
env->SetIntField(obj, objFid, c2jni(value));
|
||||
}
|
||||
|
||||
inline void setPairObjValue(const std::string& filename, const int offset,
|
||||
const jobject obj, JNIEnv* env)
|
||||
{
|
||||
jclass objClass = env->GetObjectClass(obj);
|
||||
jfieldID filenameFid = env->GetFieldID(objClass, "filename", "Ljava/lang/String;");
|
||||
env->SetObjectField(obj, filenameFid, c2jni(filename, env));
|
||||
jfieldID offsetFid = env->GetFieldID(objClass, "offset", "I");
|
||||
env->SetIntField(obj, offsetFid, offset);
|
||||
}
|
||||
|
||||
#endif // _ANDROID_JNI_UTILS_H
|
||||
243
src/aria2.cpp
243
src/aria2.cpp
@@ -2,69 +2,28 @@
|
||||
|
||||
#include "aria2.h"
|
||||
#include "xmlrpc.h"
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include "tools.h"
|
||||
#include "tools/pathTools.h"
|
||||
#include "tools/stringTools.h"
|
||||
#include "tools/otherTools.h"
|
||||
#include "downloader.h" // For AriaError
|
||||
|
||||
#ifdef _WIN32
|
||||
# define ARIA2_CMD "aria2c.exe"
|
||||
#else
|
||||
# define ARIA2_CMD "aria2c"
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define LOG_ARIA_ERROR() \
|
||||
{ \
|
||||
std::cerr << "ERROR: aria2 RPC request failed. (" << res << ")." << std::endl; \
|
||||
std::cerr << (curlErrorBuffer[0] ? curlErrorBuffer : curl_easy_strerror(res)) << std::endl; \
|
||||
}
|
||||
#include <common/otherTools.h>
|
||||
#include <common/pathTools.h>
|
||||
#include <downloader.h> // For AriaError
|
||||
|
||||
namespace kiwix {
|
||||
|
||||
namespace {
|
||||
|
||||
void pauseAnyActiveDownloads(const std::string& ariaSessionFilePath)
|
||||
{
|
||||
std::ifstream inputFile(ariaSessionFilePath);
|
||||
if ( !inputFile )
|
||||
return;
|
||||
|
||||
std::ostringstream ss;
|
||||
std::string line;
|
||||
while ( std::getline(inputFile, line) ) {
|
||||
if ( !startsWith(line, " pause=") ) {
|
||||
ss << line << "\n";
|
||||
}
|
||||
if ( !line.empty() && line[0] != ' ' && line[0] != '#' ) {
|
||||
ss << " pause=true\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::ofstream outputFile(ariaSessionFilePath);
|
||||
outputFile << ss.str();
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
Aria2::Aria2(std::string sessionFileDir):
|
||||
Aria2::Aria2():
|
||||
mp_aria(nullptr),
|
||||
m_port(42042),
|
||||
m_secret(getNewRpcSecret())
|
||||
m_secret("kiwixariarpc"),
|
||||
mp_curl(nullptr),
|
||||
m_lock(PTHREAD_MUTEX_INITIALIZER)
|
||||
{
|
||||
m_downloadDir = getDataDirectory();
|
||||
std::vector<const char*> callCmd;
|
||||
|
||||
std::string rpc_port = "--rpc-listen-port=" + to_string(m_port);
|
||||
std::string session_file = appendToDirectory(sessionFileDir, "kiwix.session");
|
||||
pauseAnyActiveDownloads(session_file);
|
||||
std::string download_dir = "--dir=" + getDataDirectory();
|
||||
std::string session_file = appendToDirectory(getDataDirectory(), "kiwix.session");
|
||||
std::string session = "--save-session=" + session_file;
|
||||
std::string inputFile = "--input-file=" + session_file;
|
||||
// std::string log_dir = "--log=\"" + logDir + "\"";
|
||||
@@ -77,21 +36,16 @@ Aria2::Aria2(std::string sessionFileDir):
|
||||
std::string rpc_secret = "--rpc-secret=" + m_secret;
|
||||
m_secret = "token:"+m_secret;
|
||||
|
||||
std::string aria2cmd = appendToDirectory(
|
||||
removeLastPathElement(getExecutablePath(true)),
|
||||
ARIA2_CMD);
|
||||
if (fileExists(aria2cmd)) {
|
||||
// A local aria2c exe exists (packaged with kiwix-desktop), use it.
|
||||
callCmd.push_back(aria2cmd.c_str());
|
||||
} else {
|
||||
// Try to use a potential installed aria2c.
|
||||
callCmd.push_back(ARIA2_CMD);
|
||||
}
|
||||
callCmd.push_back("--follow-metalink=mem");
|
||||
#ifdef _WIN32
|
||||
callCmd.push_back("aria2c.exe");
|
||||
#else
|
||||
callCmd.push_back("aria2c");
|
||||
#endif
|
||||
callCmd.push_back("--enable-rpc");
|
||||
callCmd.push_back(rpc_secret.c_str());
|
||||
callCmd.push_back(rpc_port.c_str());
|
||||
if (fileReadable(session_file)) {
|
||||
callCmd.push_back(download_dir.c_str());
|
||||
if (fileExists(session_file)) {
|
||||
callCmd.push_back(inputFile.c_str());
|
||||
}
|
||||
callCmd.push_back(session.c_str());
|
||||
@@ -107,45 +61,29 @@ Aria2::Aria2(std::string sessionFileDir):
|
||||
callCmd.push_back("--max-concurrent-downloads=42");
|
||||
callCmd.push_back("--rpc-max-request-size=6M");
|
||||
callCmd.push_back("--file-allocation=none");
|
||||
std::string launchCmd;
|
||||
for (auto &cmd : callCmd) {
|
||||
launchCmd.append(cmd).append(" ");
|
||||
}
|
||||
mp_aria = Subprocess::run(callCmd);
|
||||
mp_curl = curl_easy_init();
|
||||
curl_easy_setopt(mp_curl, CURLOPT_URL, "http://localhost/rpc");
|
||||
curl_easy_setopt(mp_curl, CURLOPT_PORT, m_port);
|
||||
curl_easy_setopt(mp_curl, CURLOPT_POST, 1L);
|
||||
|
||||
CURL* p_curl = curl_easy_init();
|
||||
char curlErrorBuffer[CURL_ERROR_SIZE];
|
||||
|
||||
curl_easy_setopt(p_curl, CURLOPT_URL, "http://localhost/rpc");
|
||||
curl_easy_setopt(p_curl, CURLOPT_PORT, m_port);
|
||||
curl_easy_setopt(p_curl, CURLOPT_POST, 1L);
|
||||
curl_easy_setopt(p_curl, CURLOPT_ERRORBUFFER, curlErrorBuffer);
|
||||
curl_easy_setopt(p_curl, CURLOPT_TIMEOUT_MS, 100);
|
||||
|
||||
typedef std::chrono::duration<double> Seconds;
|
||||
|
||||
const double MAX_WAITING_TIME_SECONDS = 1;
|
||||
const auto t0 = std::chrono::steady_clock::now();
|
||||
bool maxWaitingTimeWasExceeded = false;
|
||||
|
||||
CURLcode res = CURLE_OK;
|
||||
while ( !maxWaitingTimeWasExceeded ) {
|
||||
sleep(10);
|
||||
curlErrorBuffer[0] = 0;
|
||||
res = curl_easy_perform(p_curl);
|
||||
int watchdog = 50;
|
||||
while(--watchdog) {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(100));
|
||||
auto res = curl_easy_perform(mp_curl);
|
||||
if (res == CURLE_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!watchdog) {
|
||||
curl_easy_cleanup(mp_curl);
|
||||
throw std::runtime_error("Cannot connect to aria2c rpc");
|
||||
}
|
||||
}
|
||||
|
||||
const auto dt = std::chrono::steady_clock::now() - t0;
|
||||
const double elapsedTime = std::chrono::duration_cast<Seconds>(dt).count();
|
||||
maxWaitingTimeWasExceeded = elapsedTime > MAX_WAITING_TIME_SECONDS;
|
||||
}
|
||||
curl_easy_cleanup(p_curl);
|
||||
if ( maxWaitingTimeWasExceeded ) {
|
||||
LOG_ARIA_ERROR();
|
||||
throw std::runtime_error("Cannot connect to aria2c rpc. Aria2c launch cmd : " + launchCmd);
|
||||
}
|
||||
Aria2::~Aria2()
|
||||
{
|
||||
curl_easy_cleanup(mp_curl);
|
||||
}
|
||||
|
||||
void Aria2::close()
|
||||
@@ -156,61 +94,47 @@ void Aria2::close()
|
||||
|
||||
size_t write_callback_to_iss(char* ptr, size_t size, size_t nmemb, void* userdata)
|
||||
{
|
||||
auto outStream = static_cast<std::stringstream*>(userdata);
|
||||
outStream->write(ptr, nmemb);
|
||||
auto str = static_cast<std::stringstream*>(userdata);
|
||||
str->write(ptr, nmemb);
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
std::string Aria2::doRequest(const MethodCall& methodCall)
|
||||
{
|
||||
pthread_mutex_lock(&m_lock);
|
||||
auto requestContent = methodCall.toString();
|
||||
std::stringstream outStream;
|
||||
std::stringstream stringstream;
|
||||
CURLcode res;
|
||||
long response_code;
|
||||
char curlErrorBuffer[CURL_ERROR_SIZE];
|
||||
CURL* p_curl = curl_easy_init();
|
||||
curl_easy_setopt(p_curl, CURLOPT_URL, "http://localhost/rpc");
|
||||
curl_easy_setopt(p_curl, CURLOPT_PORT, m_port);
|
||||
curl_easy_setopt(p_curl, CURLOPT_POST, 1L);
|
||||
curl_easy_setopt(p_curl, CURLOPT_ERRORBUFFER, curlErrorBuffer);
|
||||
curl_easy_setopt(p_curl, CURLOPT_POSTFIELDSIZE, requestContent.size());
|
||||
curl_easy_setopt(p_curl, CURLOPT_POSTFIELDS, requestContent.c_str());
|
||||
curl_easy_setopt(p_curl, CURLOPT_WRITEFUNCTION, &write_callback_to_iss);
|
||||
curl_easy_setopt(p_curl, CURLOPT_WRITEDATA, &outStream);
|
||||
curlErrorBuffer[0] = 0;
|
||||
res = curl_easy_perform(p_curl);
|
||||
if (res != CURLE_OK) {
|
||||
LOG_ARIA_ERROR();
|
||||
curl_easy_cleanup(p_curl);
|
||||
throw std::runtime_error("Cannot perform request");
|
||||
curl_easy_setopt(mp_curl, CURLOPT_POSTFIELDSIZE, requestContent.size());
|
||||
curl_easy_setopt(mp_curl, CURLOPT_POSTFIELDS, requestContent.c_str());
|
||||
curl_easy_setopt(mp_curl, CURLOPT_WRITEFUNCTION, &write_callback_to_iss);
|
||||
curl_easy_setopt(mp_curl, CURLOPT_WRITEDATA, &stringstream);
|
||||
res = curl_easy_perform(mp_curl);
|
||||
if (res == CURLE_OK) {
|
||||
long response_code;
|
||||
curl_easy_getinfo(mp_curl, CURLINFO_RESPONSE_CODE, &response_code);
|
||||
pthread_mutex_unlock(&m_lock);
|
||||
if (response_code != 200) {
|
||||
throw std::runtime_error("Invalid return code from aria");
|
||||
}
|
||||
auto responseContent = stringstream.str();
|
||||
MethodResponse response(responseContent);
|
||||
if (response.isFault()) {
|
||||
throw AriaError(response.getFault().getFaultString());
|
||||
}
|
||||
return responseContent;
|
||||
}
|
||||
curl_easy_getinfo(p_curl, CURLINFO_RESPONSE_CODE, &response_code);
|
||||
curl_easy_cleanup(p_curl);
|
||||
|
||||
auto responseContent = outStream.str();
|
||||
if (response_code != 200) {
|
||||
std::cerr << "ERROR: Invalid return code (" << response_code << ") from aria :" << std::endl;
|
||||
std::cerr << responseContent << std::endl;
|
||||
throw std::runtime_error("Invalid return code from aria");
|
||||
}
|
||||
|
||||
MethodResponse response(responseContent);
|
||||
if (response.isFault()) {
|
||||
throw AriaError(response.getFault().getFaultString());
|
||||
}
|
||||
return responseContent;
|
||||
pthread_mutex_unlock(&m_lock);
|
||||
throw std::runtime_error("Cannot perform request");
|
||||
}
|
||||
|
||||
std::string Aria2::addUri(const std::vector<std::string>& uris, const std::vector<std::pair<std::string, std::string>>& options)
|
||||
std::string Aria2::addUri(const std::vector<std::string>& uris)
|
||||
{
|
||||
MethodCall methodCall("aria2.addUri", m_secret);
|
||||
auto uriParams = methodCall.newParamValue().getArray();
|
||||
for (auto& uri : uris) {
|
||||
uriParams.addValue().set(uri);
|
||||
}
|
||||
for (auto& option : options) {
|
||||
methodCall.newParamValue().getStruct().addMember(option.first).getValue().set(option.second);
|
||||
}
|
||||
auto ret = doRequest(methodCall);
|
||||
MethodResponse response(ret);
|
||||
return response.getParamValue(0).getAsS();
|
||||
@@ -229,18 +153,12 @@ std::string Aria2::tellStatus(const std::string& gid, const std::vector<std::str
|
||||
return doRequest(methodCall);
|
||||
}
|
||||
|
||||
std::string Aria2::getNewRpcSecret()
|
||||
{
|
||||
std::string uuid = gen_uuid("");
|
||||
uuid.erase(std::remove(uuid.begin(), uuid.end(), '-'));
|
||||
return uuid.substr(0, 9);
|
||||
}
|
||||
|
||||
std::vector<std::string> Aria2::tellActive()
|
||||
{
|
||||
MethodCall methodCall("aria2.tellActive", m_secret);
|
||||
auto statusArray = methodCall.newParamValue().getArray();
|
||||
statusArray.addValue().set(std::string("gid"));
|
||||
statusArray.addValue().set(std::string("following"));
|
||||
auto responseContent = doRequest(methodCall);
|
||||
MethodResponse response(responseContent);
|
||||
std::vector<std::string> activeGID;
|
||||
@@ -255,27 +173,6 @@ std::vector<std::string> Aria2::tellActive()
|
||||
return activeGID;
|
||||
}
|
||||
|
||||
std::vector<std::string> Aria2::tellWaiting()
|
||||
{
|
||||
MethodCall methodCall("aria2.tellWaiting", m_secret);
|
||||
methodCall.newParamValue().set(0);
|
||||
methodCall.newParamValue().set(99); // max number of downloads to be returned, don't know how to set this properly assumed that there will not be more than 99 paused downloads.
|
||||
auto statusArray = methodCall.newParamValue().getArray();
|
||||
statusArray.addValue().set(std::string("gid"));
|
||||
auto responseContent = doRequest(methodCall);
|
||||
MethodResponse response(responseContent);
|
||||
std::vector<std::string> waitingGID;
|
||||
int index = 0;
|
||||
while(true) {
|
||||
try {
|
||||
auto structNode = response.getParamValue(0).getArray().getValue(index++).getStruct();
|
||||
auto gidNode = structNode.getMember("gid");
|
||||
waitingGID.push_back(gidNode.getValue().getAsS());
|
||||
} catch (InvalidRPCNode& e) { break; }
|
||||
}
|
||||
return waitingGID;
|
||||
}
|
||||
|
||||
void Aria2::saveSession()
|
||||
{
|
||||
MethodCall methodCall("aria2.saveSession", m_secret);
|
||||
@@ -289,25 +186,5 @@ void Aria2::shutdown()
|
||||
doRequest(methodCall);
|
||||
}
|
||||
|
||||
void Aria2::pause(const std::string& gid)
|
||||
{
|
||||
MethodCall methodCall("aria2.pause", m_secret);
|
||||
methodCall.newParamValue().set(gid);
|
||||
doRequest(methodCall);
|
||||
}
|
||||
|
||||
void Aria2::unpause(const std::string& gid)
|
||||
{
|
||||
MethodCall methodCall("aria2.unpause", m_secret);
|
||||
methodCall.newParamValue().set(gid);
|
||||
doRequest(methodCall);
|
||||
}
|
||||
|
||||
void Aria2::remove(const std::string& gid)
|
||||
{
|
||||
MethodCall methodCall("aria2.remove", m_secret);
|
||||
methodCall.newParamValue().set(gid);
|
||||
doRequest(methodCall);
|
||||
}
|
||||
|
||||
} // end namespace kiwix
|
||||
|
||||
16
src/aria2.h
16
src/aria2.h
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <curl/curl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
namespace kiwix {
|
||||
|
||||
@@ -22,23 +23,22 @@ class Aria2
|
||||
std::unique_ptr<Subprocess> mp_aria;
|
||||
int m_port;
|
||||
std::string m_secret;
|
||||
std::string m_downloadDir;
|
||||
CURL* mp_curl;
|
||||
pthread_mutex_t m_lock;
|
||||
|
||||
std::string doRequest(const MethodCall& methodCall);
|
||||
|
||||
public:
|
||||
explicit Aria2(std::string sessionFileDir);
|
||||
virtual ~Aria2() = default;
|
||||
Aria2();
|
||||
virtual ~Aria2();
|
||||
void close();
|
||||
|
||||
std::string addUri(const std::vector<std::string>& uri, const std::vector<std::pair<std::string, std::string>>& options = {});
|
||||
std::string addUri(const std::vector<std::string>& uri);
|
||||
std::string tellStatus(const std::string& gid, const std::vector<std::string>& statusKey);
|
||||
static std::string getNewRpcSecret();
|
||||
std::vector<std::string> tellActive();
|
||||
std::vector<std::string> tellWaiting();
|
||||
void saveSession();
|
||||
void shutdown();
|
||||
void pause(const std::string& gid);
|
||||
void unpause(const std::string& gid);
|
||||
void remove(const std::string& gid);
|
||||
};
|
||||
|
||||
}; //end namespace kiwix
|
||||
|
||||
245
src/book.cpp
245
src/book.cpp
@@ -18,80 +18,78 @@
|
||||
*/
|
||||
|
||||
#include "book.h"
|
||||
#include "reader.h"
|
||||
|
||||
#include "tools.h"
|
||||
#include "tools/base64.h"
|
||||
#include "tools/regexTools.h"
|
||||
#include "tools/networkTools.h"
|
||||
#include "tools/otherTools.h"
|
||||
#include "tools/stringTools.h"
|
||||
#include "tools/pathTools.h"
|
||||
#include "tools/archiveTools.h"
|
||||
#include "common/base64.h"
|
||||
#include "common/regexTools.h"
|
||||
#include "common/networkTools.h"
|
||||
|
||||
#include <zim/archive.h>
|
||||
#include <zim/item.h>
|
||||
#include <pugixml.hpp>
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
/* Constructor */
|
||||
Book::Book() :
|
||||
m_pathValid(false),
|
||||
m_readOnly(false)
|
||||
Book::Book() : m_readOnly(false)
|
||||
{
|
||||
}
|
||||
|
||||
/* Destructor */
|
||||
Book::~Book()
|
||||
{
|
||||
}
|
||||
|
||||
Book::Illustrations Book::getIllustrations() const
|
||||
{
|
||||
return m_illustrations;
|
||||
}
|
||||
|
||||
bool Book::update(const kiwix::Book& other)
|
||||
{
|
||||
if (m_readOnly)
|
||||
return false;
|
||||
|
||||
if (m_id != other.m_id)
|
||||
return false;
|
||||
m_readOnly = other.m_readOnly;
|
||||
|
||||
*this = other;
|
||||
if (m_path.empty()) {
|
||||
m_path = other.m_path;
|
||||
}
|
||||
|
||||
if (m_url.empty()) {
|
||||
m_url = other.m_url;
|
||||
}
|
||||
|
||||
if (m_tags.empty()) {
|
||||
m_tags = other.m_tags;
|
||||
}
|
||||
|
||||
if (m_name.empty()) {
|
||||
m_name = other.m_name;
|
||||
}
|
||||
|
||||
if (m_indexPath.empty()) {
|
||||
m_indexPath = other.m_indexPath;
|
||||
m_indexType = other.m_indexType;
|
||||
}
|
||||
|
||||
if (m_faviconMimeType.empty()) {
|
||||
m_favicon = other.m_favicon;
|
||||
m_faviconMimeType = other.m_faviconMimeType;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Book::update(const zim::Archive& archive) {
|
||||
m_path = archive.getFilename();
|
||||
m_pathValid = true;
|
||||
m_id = std::string(archive.getUuid());
|
||||
m_title = getArchiveTitle(archive);
|
||||
m_description = getMetaDescription(archive);
|
||||
m_language = getMetaLanguage(archive);
|
||||
m_creator = getMetaCreator(archive);
|
||||
m_publisher = getMetaPublisher(archive);
|
||||
m_date = getMetaDate(archive);
|
||||
m_name = getMetaName(archive);
|
||||
m_flavour = getMetaFlavour(archive);
|
||||
m_tags = getMetaTags(archive);
|
||||
m_category = getCategoryFromTags();
|
||||
m_articleCount = archive.getArticleCount();
|
||||
m_mediaCount = archive.getMediaCount();
|
||||
m_size = static_cast<uint64_t>(getArchiveFileSize(archive)) << 10;
|
||||
void Book::update(const kiwix::Reader& reader)
|
||||
{
|
||||
m_path = reader.getZimFilePath();
|
||||
m_id = reader.getId();
|
||||
m_description = reader.getDescription();
|
||||
m_language = reader.getLanguage();
|
||||
m_date = reader.getDate();
|
||||
m_creator = reader.getCreator();
|
||||
m_publisher = reader.getPublisher();
|
||||
m_title = reader.getTitle();
|
||||
m_name = reader.getName();
|
||||
m_tags = reader.getTags();
|
||||
m_origId = reader.getOrigId();
|
||||
m_articleCount = reader.getArticleCount();
|
||||
m_mediaCount = reader.getMediaCount();
|
||||
m_size = static_cast<uint64_t>(reader.getFileSize()) << 10;
|
||||
|
||||
m_illustrations.clear();
|
||||
for ( const auto& illustrationInfo : archive.getIllustrationInfos() ) {
|
||||
const auto illustration = std::make_shared<Illustration>();
|
||||
const zim::Item illustrationItem = archive.getIllustrationItem(illustrationInfo);
|
||||
illustration->width = illustrationInfo.width;
|
||||
illustration->height = illustrationInfo.height;
|
||||
illustration->mimeType = illustrationItem.getMimetype();
|
||||
illustration->data = illustrationItem.getData();
|
||||
// NOTE: illustration->url is left uninitialized
|
||||
m_illustrations.push_back(illustration);
|
||||
}
|
||||
reader.getFavicon(m_favicon, m_faviconMimeType);
|
||||
}
|
||||
|
||||
#define ATTR(name) node.attribute(name).value()
|
||||
@@ -103,47 +101,36 @@ void Book::updateFromXml(const pugi::xml_node& node, const std::string& baseDir)
|
||||
path = computeAbsolutePath(baseDir, path);
|
||||
}
|
||||
m_path = path;
|
||||
m_pathValid = fileReadable(path);
|
||||
path = ATTR("indexPath");
|
||||
if (!path.empty()) {
|
||||
if (isRelativePath(path)) {
|
||||
path = computeAbsolutePath(baseDir, path);
|
||||
}
|
||||
m_indexPath = path;
|
||||
m_indexType = XAPIAN;
|
||||
}
|
||||
m_title = ATTR("title");
|
||||
m_name = ATTR("name");
|
||||
m_tags = ATTR("tags");
|
||||
m_description = ATTR("description");
|
||||
m_language = ATTR("language");
|
||||
m_date = ATTR("date");
|
||||
m_creator = ATTR("creator");
|
||||
m_publisher = ATTR("publisher");
|
||||
m_date = ATTR("date");
|
||||
m_url = ATTR("url");
|
||||
m_name = ATTR("name");
|
||||
m_flavour = ATTR("flavour");
|
||||
m_tags = ATTR("tags");
|
||||
m_origId = ATTR("origId");
|
||||
m_articleCount = strtoull(ATTR("articleCount"), 0, 0);
|
||||
m_mediaCount = strtoull(ATTR("mediaCount"), 0, 0);
|
||||
m_size = strtoull(ATTR("size"), 0, 0) << 10;
|
||||
const std::string faviconMimeType = ATTR("faviconMimeType");
|
||||
const std::string faviconBase64EncodedData = ATTR("favicon");
|
||||
if ( !faviconMimeType.empty() && !faviconBase64EncodedData.empty() ) {
|
||||
const auto favicon = std::make_shared<Illustration>();
|
||||
favicon->data = base64_decode(faviconBase64EncodedData);
|
||||
favicon->mimeType = faviconMimeType;
|
||||
favicon->url = ATTR("faviconUrl");
|
||||
m_illustrations.assign(1, favicon);
|
||||
}
|
||||
m_favicon = base64_decode(ATTR("favicon"));
|
||||
m_faviconMimeType = ATTR("faviconMimeType");
|
||||
try {
|
||||
m_downloadId = ATTR("downloadId");
|
||||
} catch(...) {}
|
||||
const auto catattr = node.attribute("category");
|
||||
m_category = catattr.empty() ? getCategoryFromTags() : catattr.value();
|
||||
}
|
||||
#undef ATTR
|
||||
|
||||
|
||||
static std::string fromOpdsDate(const std::string& date)
|
||||
{
|
||||
//The opds date use the standard <YYYY>-<MM>-<DD>T<HH>:<mm>:<SS>Z
|
||||
//and we want <YYYY>-<MM>-<DD>. That's easy, let's take the first 10 char
|
||||
return date.substr(0, 10);
|
||||
}
|
||||
|
||||
|
||||
#define VALUE(name) node.child(name).child_value()
|
||||
void Book::updateFromOpds(const pugi::xml_node& node, const std::string& urlHost)
|
||||
{
|
||||
@@ -151,22 +138,11 @@ void Book::updateFromOpds(const pugi::xml_node& node, const std::string& urlHost
|
||||
if (!m_id.compare(0, 9, "urn:uuid:")) {
|
||||
m_id.erase(0, 9);
|
||||
}
|
||||
// No path on opds.
|
||||
m_title = VALUE("title");
|
||||
m_description = VALUE("summary");
|
||||
m_description = VALUE("description");
|
||||
m_language = VALUE("language");
|
||||
m_date = VALUE("updated");
|
||||
m_creator = node.child("author").child("name").child_value();
|
||||
m_publisher = node.child("publisher").child("name").child_value();
|
||||
const std::string dcIssuedDate = VALUE("dc:issued");
|
||||
m_date = dcIssuedDate.empty() ? VALUE("updated") : dcIssuedDate;
|
||||
m_date = fromOpdsDate(m_date);
|
||||
m_name = VALUE("name");
|
||||
m_flavour = VALUE("flavour");
|
||||
m_tags = VALUE("tags");
|
||||
const auto catnode = node.child("category");
|
||||
m_category = catnode.empty() ? getCategoryFromTags() : catnode.child_value();
|
||||
m_articleCount = strtoull(VALUE("articleCount"), 0, 0);
|
||||
m_mediaCount = strtoull(VALUE("mediaCount"), 0, 0);
|
||||
for(auto linkNode = node.child("link"); linkNode;
|
||||
linkNode = linkNode.next_sibling("link")) {
|
||||
std::string rel = linkNode.attribute("rel").value();
|
||||
@@ -176,22 +152,19 @@ void Book::updateFromOpds(const pugi::xml_node& node, const std::string& urlHost
|
||||
m_size = strtoull(linkNode.attribute("length").value(), 0, 0);
|
||||
}
|
||||
if (rel == "http://opds-spec.org/image/thumbnail") {
|
||||
const auto favicon = std::make_shared<Illustration>();
|
||||
favicon->data.clear();
|
||||
favicon->url = urlHost + linkNode.attribute("href").value();
|
||||
favicon->mimeType = linkNode.attribute("type").value();
|
||||
m_illustrations.assign(1, favicon);
|
||||
m_faviconUrl = urlHost + linkNode.attribute("href").value();
|
||||
m_faviconMimeType = linkNode.attribute("type").value();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#undef VALUE
|
||||
|
||||
std::string Book::getHumanReadableIdFromPath() const
|
||||
std::string Book::getHumanReadableIdFromPath()
|
||||
{
|
||||
std::string id = m_path;
|
||||
if (!id.empty()) {
|
||||
id = kiwix::removeAccents(id);
|
||||
kiwix::removeAccents(id);
|
||||
|
||||
#ifdef _WIN32
|
||||
id = replaceRegex(id, "", "^.*\\\\");
|
||||
@@ -213,84 +186,22 @@ void Book::setPath(const std::string& path)
|
||||
: path;
|
||||
}
|
||||
|
||||
const Book::Illustration Book::missingDefaultIllustration;
|
||||
|
||||
std::shared_ptr<const Book::Illustration> Book::getIllustration(unsigned int size) const
|
||||
void Book::setIndexPath(const std::string& indexPath)
|
||||
{
|
||||
for ( const auto& ilPtr : m_illustrations ) {
|
||||
if (ilPtr->width == size && ilPtr->height == size) {
|
||||
return ilPtr;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Cannot find illustration");
|
||||
}
|
||||
|
||||
const Book::Illustration& Book::getDefaultIllustration() const
|
||||
{
|
||||
try {
|
||||
return *getIllustration(48);
|
||||
} catch (...) {
|
||||
return missingDefaultIllustration;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& Book::Illustration::getData() const
|
||||
{
|
||||
if (data.empty() && !url.empty()) {
|
||||
const std::lock_guard<std::mutex> l(mutex);
|
||||
if ( data.empty() ) {
|
||||
try {
|
||||
data = download(url);
|
||||
} catch(...) {
|
||||
std::cerr << "Cannot download favicon from " << url;
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
m_indexPath = isRelativePath(indexPath)
|
||||
? computeAbsolutePath(getCurrentDirectory(), indexPath)
|
||||
: indexPath;
|
||||
}
|
||||
|
||||
const std::string& Book::getFavicon() const {
|
||||
return getDefaultIllustration().getData();
|
||||
}
|
||||
|
||||
const std::string& Book::getFaviconUrl() const
|
||||
{
|
||||
return getDefaultIllustration().url;
|
||||
}
|
||||
|
||||
const std::string& Book::getFaviconMimeType() const
|
||||
{
|
||||
return getDefaultIllustration().mimeType;
|
||||
}
|
||||
|
||||
std::string Book::getTagStr(const std::string& tagName) const {
|
||||
return getTagValueFromTagList(convertTags(m_tags), tagName);
|
||||
}
|
||||
|
||||
bool Book::getTagBool(const std::string& tagName) const {
|
||||
return convertStrToBool(getTagStr(tagName));
|
||||
}
|
||||
|
||||
std::string Book::getCategory() const
|
||||
{
|
||||
return m_category;
|
||||
}
|
||||
|
||||
std::string Book::getCategoryFromTags() const
|
||||
{
|
||||
try
|
||||
{
|
||||
return getTagStr("category");
|
||||
if (m_favicon.empty() && !m_faviconUrl.empty()) {
|
||||
try {
|
||||
m_favicon = download(m_faviconUrl);
|
||||
} catch(...) {
|
||||
std::cerr << "Cannot download favicon from " << m_faviconUrl;
|
||||
}
|
||||
}
|
||||
catch ( const std::out_of_range& )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<std::string> Book::getLanguages() const
|
||||
{
|
||||
return kiwix::split(m_language, ",");
|
||||
return m_favicon;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "bookmark.h"
|
||||
#include "book.h"
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
/* Constructor */
|
||||
Bookmark::Bookmark()
|
||||
{
|
||||
}
|
||||
|
||||
Bookmark::Bookmark(const Book& book, const std::string& path, const std::string& title):
|
||||
m_bookId(book.getId()),
|
||||
m_bookTitle(book.getTitle()),
|
||||
m_bookName(book.getName()),
|
||||
m_bookFlavour(book.getFlavour()),
|
||||
m_url(path),
|
||||
m_title(title),
|
||||
m_language(book.getCommaSeparatedLanguages()),
|
||||
m_date(book.getDate())
|
||||
{}
|
||||
|
||||
/* Destructor */
|
||||
Bookmark::~Bookmark()
|
||||
{
|
||||
}
|
||||
|
||||
void Bookmark::updateFromXml(const pugi::xml_node& node)
|
||||
{
|
||||
auto bookNode = node.child("book");
|
||||
m_bookId = bookNode.child("id").child_value();
|
||||
m_bookTitle = bookNode.child("title").child_value();
|
||||
m_bookName = bookNode.child("name").child_value();
|
||||
m_bookFlavour = bookNode.child("flavour").child_value();
|
||||
m_language = bookNode.child("language").child_value();
|
||||
m_date = bookNode.child("date").child_value();
|
||||
m_title = node.child("title").child_value();
|
||||
m_url = node.child("url").child_value();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
base64.cpp and base64.h
|
||||
|
||||
Copyright (C) 2004-2008 René Nyffenegger
|
||||
@@ -24,10 +24,10 @@
|
||||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
*/
|
||||
|
||||
#include <tools/base64.h>
|
||||
#include <common/base64.h>
|
||||
#include <iostream>
|
||||
|
||||
static const std::string base64_chars =
|
||||
static const std::string base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
209
src/common/networkTools.cpp
Normal file
209
src/common/networkTools.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright 2012 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <common/networkTools.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
std::map<std::string, std::string> kiwix::getNetworkInterfaces()
|
||||
{
|
||||
std::map<std::string, std::string> interfaces;
|
||||
|
||||
#ifdef _WIN32
|
||||
SOCKET sd = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0);
|
||||
if (sd == (SOCKET)SOCKET_ERROR) {
|
||||
std::cerr << "Failed to get a socket. Error " << WSAGetLastError()
|
||||
<< std::endl;
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
INTERFACE_INFO InterfaceList[20];
|
||||
unsigned long nBytesReturned;
|
||||
if (WSAIoctl(sd,
|
||||
SIO_GET_INTERFACE_LIST,
|
||||
0,
|
||||
0,
|
||||
&InterfaceList,
|
||||
sizeof(InterfaceList),
|
||||
&nBytesReturned,
|
||||
0,
|
||||
0)
|
||||
== SOCKET_ERROR) {
|
||||
std::cerr << "Failed calling WSAIoctl: error " << WSAGetLastError()
|
||||
<< std::endl;
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
int nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
|
||||
for (int i = 0; i < nNumInterfaces; ++i) {
|
||||
sockaddr_in* pAddress;
|
||||
pAddress = (sockaddr_in*)&(InterfaceList[i].iiAddress);
|
||||
|
||||
/* Add to the map */
|
||||
std::string interfaceName = std::string(inet_ntoa(pAddress->sin_addr));
|
||||
std::string interfaceIp = std::string(inet_ntoa(pAddress->sin_addr));
|
||||
interfaces.insert(
|
||||
std::pair<std::string, std::string>(interfaceName, interfaceIp));
|
||||
}
|
||||
#else
|
||||
/* Get Network interfaces information */
|
||||
char buf[16384];
|
||||
struct ifconf ifconf;
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, 0); /* Only IPV4 */
|
||||
ifconf.ifc_len = sizeof buf;
|
||||
ifconf.ifc_buf = buf;
|
||||
if (ioctl(fd, SIOCGIFCONF, &ifconf) != 0) {
|
||||
perror("ioctl(SIOCGIFCONF)");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Go through each interface */
|
||||
int i;
|
||||
size_t len;
|
||||
struct ifreq* ifreq;
|
||||
ifreq = ifconf.ifc_req;
|
||||
for (i = 0; i < ifconf.ifc_len;) {
|
||||
if (ifreq->ifr_addr.sa_family == AF_INET) {
|
||||
/* Get the network interface ip */
|
||||
char host[128] = {0};
|
||||
const int error = getnameinfo(&(ifreq->ifr_addr),
|
||||
sizeof ifreq->ifr_addr,
|
||||
host,
|
||||
sizeof host,
|
||||
0,
|
||||
0,
|
||||
NI_NUMERICHOST);
|
||||
if (!error) {
|
||||
std::string interfaceName = std::string(ifreq->ifr_name);
|
||||
std::string interfaceIp = std::string(host);
|
||||
/* Add to the map */
|
||||
interfaces.insert(
|
||||
std::pair<std::string, std::string>(interfaceName, interfaceIp));
|
||||
} else {
|
||||
perror("getnameinfo()");
|
||||
}
|
||||
}
|
||||
|
||||
/* some systems have ifr_addr.sa_len and adjust the length that
|
||||
* way, but not mine. weird */
|
||||
#ifndef __linux__
|
||||
len = IFNAMSIZ + ifreq->ifr_addr.sa_len;
|
||||
#else
|
||||
len = sizeof *ifreq;
|
||||
#endif
|
||||
ifreq = (struct ifreq*)((char*)ifreq + len);
|
||||
i += len;
|
||||
}
|
||||
#endif
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
std::string kiwix::getBestPublicIp()
|
||||
{
|
||||
std::map<std::string, std::string> interfaces = kiwix::getNetworkInterfaces();
|
||||
|
||||
#ifndef _WIN32
|
||||
const char* const prioritizedNames[]
|
||||
= {"eth0", "eth1", "wlan0", "wlan1", "en0", "en1"};
|
||||
const int count = (sizeof prioritizedNames) / (sizeof prioritizedNames[0]);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
std::map<std::string, std::string>::const_iterator it
|
||||
= interfaces.find(prioritizedNames[i]);
|
||||
if (it != interfaces.end()) {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (std::map<std::string, std::string>::iterator iter = interfaces.begin();
|
||||
iter != interfaces.end();
|
||||
++iter) {
|
||||
std::string interfaceIp = iter->second;
|
||||
if (interfaceIp.length() >= 7 && interfaceIp.substr(0, 7) == "192.168") {
|
||||
return interfaceIp;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::string>::iterator iter = interfaces.begin();
|
||||
iter != interfaces.end();
|
||||
++iter) {
|
||||
std::string interfaceIp = iter->second;
|
||||
if (interfaceIp.length() >= 7 && interfaceIp.substr(0, 7) == "172.16.") {
|
||||
return interfaceIp;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::string>::iterator iter = interfaces.begin();
|
||||
iter != interfaces.end();
|
||||
++iter) {
|
||||
std::string interfaceIp = iter->second;
|
||||
if (interfaceIp.length() >= 3 && interfaceIp.substr(0, 3) == "10.") {
|
||||
return interfaceIp;
|
||||
}
|
||||
}
|
||||
|
||||
return "127.0.0.1";
|
||||
}
|
||||
|
||||
size_t write_callback_to_iss(char* ptr, size_t size, size_t nmemb, void* userdata)
|
||||
{
|
||||
auto str = static_cast<std::stringstream*>(userdata);
|
||||
str->write(ptr, nmemb);
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
std::string kiwix::download(const std::string& url) {
|
||||
auto curl = curl_easy_init();
|
||||
std::stringstream ss;
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_callback_to_iss);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ss);
|
||||
auto res = curl_easy_perform(curl);
|
||||
if (res != CURLE_OK) {
|
||||
curl_easy_cleanup(curl);
|
||||
throw std::runtime_error("Cannot perform request");
|
||||
}
|
||||
long response_code;
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
|
||||
curl_easy_cleanup(curl);
|
||||
if (response_code != 200) {
|
||||
throw std::runtime_error("Invalid return code from server");
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
326
src/common/otherTools.cpp
Normal file
326
src/common/otherTools.cpp
Normal file
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright 2014 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <common/otherTools.h>
|
||||
#include <map>
|
||||
|
||||
static std::map<std::string, std::string> codeisomapping {
|
||||
//a
|
||||
{ "ad", "and" },
|
||||
{ "ae", "are" },
|
||||
{ "af", "afg" },
|
||||
{ "ag", "atg" },
|
||||
{ "ai", "aia" },
|
||||
{ "al", "alb" },
|
||||
{ "am", "arm" },
|
||||
{ "an", "ant" },
|
||||
{ "ao", "ago" },
|
||||
{ "aq", "ata" },
|
||||
{ "ar", "arg" },
|
||||
{ "as", "asm" },
|
||||
{ "at", "aut" },
|
||||
{ "au", "aus" },
|
||||
{ "aw", "abw" },
|
||||
{ "ax", "ala" },
|
||||
{ "az", "aze" },
|
||||
//b
|
||||
{ "ba", "bih" },
|
||||
{ "bb", "brb" },
|
||||
{ "bd", "bgd" },
|
||||
{ "be", "bel" },
|
||||
{ "bf", "bfa" },
|
||||
{ "bg", "bgr" },
|
||||
{ "bh", "bhr" },
|
||||
{ "bi", "bdi" },
|
||||
{ "bj", "ben" },
|
||||
{ "bl", "blm" },
|
||||
{ "bn", "brn" },
|
||||
{ "bm", "bmu" },
|
||||
{ "bo", "bol" },
|
||||
{ "br", "bra" },
|
||||
{ "bs", "bhs" },
|
||||
{ "bt", "btn" },
|
||||
{ "bv", "bvt" },
|
||||
{ "bw", "bwa" },
|
||||
{ "by", "blr" },
|
||||
{ "bz", "blz" },
|
||||
//c
|
||||
{ "ca", "can" },
|
||||
{ "cc", "cck" },
|
||||
{ "cd", "cod" },
|
||||
{ "cf", "caf" },
|
||||
{ "cg", "cog" },
|
||||
{ "ch", "che" },
|
||||
{ "ci", "civ" },
|
||||
{ "ck", "cok" },
|
||||
{ "cl", "chl" },
|
||||
{ "cm", "cmr" },
|
||||
{ "cn", "chn" },
|
||||
{ "co", "col" },
|
||||
{ "cr", "cri" },
|
||||
{ "cu", "cub" },
|
||||
{ "cv", "cpv" },
|
||||
{ "cx", "cxr" },
|
||||
{ "cy", "cyp" },
|
||||
{ "cz", "cze" },
|
||||
//d
|
||||
{ "de", "deu" },
|
||||
{ "dj", "dji" },
|
||||
{ "dk", "dnk" },
|
||||
{ "dm", "dma" },
|
||||
{ "do", "dom" },
|
||||
{ "dz", "dza" },
|
||||
//e
|
||||
{ "ec", "ecu" },
|
||||
{ "ee", "est" },
|
||||
{ "eg", "egy" },
|
||||
{ "eh", "esh" },
|
||||
{ "en", "eng" },
|
||||
{ "er", "eri" },
|
||||
{ "es", "esp" },
|
||||
{ "et", "eth" },
|
||||
//f
|
||||
{ "fi", "fin" },
|
||||
{ "fj", "fji" },
|
||||
{ "fk", "flk" },
|
||||
{ "fm", "fsm" },
|
||||
{ "fo", "fro" },
|
||||
{ "fr", "fra" },
|
||||
//g
|
||||
{ "ga", "gab" },
|
||||
{ "gb", "gbr" },
|
||||
{ "gd", "grd" },
|
||||
{ "ge", "geo" },
|
||||
{ "gf", "guf" },
|
||||
{ "gg", "ggy" },
|
||||
{ "gh", "gha" },
|
||||
{ "gi", "gib" },
|
||||
{ "gl", "grl" },
|
||||
{ "gm", "gmb" },
|
||||
{ "gn", "gin" },
|
||||
{ "gp", "glp" },
|
||||
{ "gq", "gnq" },
|
||||
{ "gr", "grc" },
|
||||
{ "gs", "sgs" },
|
||||
{ "gt", "gtm" },
|
||||
{ "gu", "gum" },
|
||||
{ "gw", "gnb" },
|
||||
{ "gy", "guy" },
|
||||
//h
|
||||
{ "hk", "hkg" },
|
||||
{ "hm", "hmd" },
|
||||
{ "hn", "hnd" },
|
||||
{ "hr", "hrv" },
|
||||
{ "ht", "hti" },
|
||||
{ "hu", "hun" },
|
||||
//i
|
||||
{ "id", "idn" },
|
||||
{ "ie", "irl" },
|
||||
{ "il", "isr" },
|
||||
{ "im", "imn" },
|
||||
{ "in", "ind" },
|
||||
{ "io", "iot" },
|
||||
{ "iq", "irq" },
|
||||
{ "ir", "irn" },
|
||||
{ "is", "isl" },
|
||||
{ "it", "ita" },
|
||||
//j
|
||||
{ "je", "jey" },
|
||||
{ "jm", "jam" },
|
||||
{ "jo", "jor" },
|
||||
{ "jp", "jpn" },
|
||||
//k
|
||||
{ "ke", "ken" },
|
||||
{ "kg", "kgz" },
|
||||
{ "kh", "khm" },
|
||||
{ "ki", "kir" },
|
||||
{ "km", "com" },
|
||||
{ "kn", "kna" },
|
||||
{ "kp", "prk" },
|
||||
{ "kr", "kor" },
|
||||
{ "kw", "kwt" },
|
||||
{ "ky", "cym" },
|
||||
{ "kz", "kaz" },
|
||||
//l
|
||||
{ "la", "lao" },
|
||||
{ "lb", "lbn" },
|
||||
{ "lc", "lca" },
|
||||
{ "li", "lie" },
|
||||
{ "lk", "lka" },
|
||||
{ "lr", "lbr" },
|
||||
{ "ls", "lso" },
|
||||
{ "lt", "ltu" },
|
||||
{ "lu", "lux" },
|
||||
{ "lv", "lva" },
|
||||
{ "ly", "lby" },
|
||||
//m
|
||||
{ "ma", "mar" },
|
||||
{ "mc", "mco" },
|
||||
{ "md", "mda" },
|
||||
{ "me", "mne" },
|
||||
{ "mf", "maf" },
|
||||
{ "mg", "mdg" },
|
||||
{ "mh", "mhl" },
|
||||
{ "mk", "mkd" },
|
||||
{ "ml", "mli" },
|
||||
{ "mm", "mmr" },
|
||||
{ "mn", "mng" },
|
||||
{ "mo", "mac" },
|
||||
{ "mp", "mnp" },
|
||||
{ "mq", "mtq" },
|
||||
{ "mr", "mrt" },
|
||||
{ "ms", "msr" },
|
||||
{ "mt", "mlt" },
|
||||
{ "mu", "mus" },
|
||||
{ "mv", "mdv" },
|
||||
{ "mw", "mwi" },
|
||||
{ "mx", "mex" },
|
||||
{ "my", "mys" },
|
||||
{ "mz", "moz" },
|
||||
//n
|
||||
{ "na", "nam" },
|
||||
{ "nc", "ncl" },
|
||||
{ "ne", "ner" },
|
||||
{ "nf", "nfk" },
|
||||
{ "ng", "nga" },
|
||||
{ "ni", "nic" },
|
||||
{ "nl", "nld" },
|
||||
{ "no", "nor" },
|
||||
{ "np", "npl" },
|
||||
{ "nr", "nru" },
|
||||
{ "nu", "niu" },
|
||||
{ "nz", "nzl" },
|
||||
//o
|
||||
{ "om", "omn" },
|
||||
//p
|
||||
{ "pa", "pan" },
|
||||
{ "pe", "per" },
|
||||
{ "pf", "pyf" },
|
||||
{ "pg", "png" },
|
||||
{ "ph", "phl" },
|
||||
{ "pk", "pak" },
|
||||
{ "pl", "pol" },
|
||||
{ "pm", "spm" },
|
||||
{ "pn", "pcn" },
|
||||
{ "pr", "pri" },
|
||||
{ "ps", "pse" },
|
||||
{ "pt", "prt" },
|
||||
{ "pw", "plw" },
|
||||
{ "py", "pry" },
|
||||
//q
|
||||
{ "qa", "qat" },
|
||||
//r
|
||||
{ "re", "reu" },
|
||||
{ "ro", "rou" },
|
||||
{ "rs", "srb" },
|
||||
{ "ru", "rus" },
|
||||
{ "rw", "rwa" },
|
||||
//s
|
||||
{ "sa", "sau" },
|
||||
{ "sb", "slb" },
|
||||
{ "sc", "syc" },
|
||||
{ "sd", "sdn" },
|
||||
{ "se", "swe" },
|
||||
{ "sg", "sgp" },
|
||||
{ "sh", "shn" },
|
||||
{ "si", "svn" },
|
||||
{ "sj", "sjm" },
|
||||
{ "sk", "svk" },
|
||||
{ "sl", "sle" },
|
||||
{ "sm", "smr" },
|
||||
{ "sn", "sen" },
|
||||
{ "so", "som" },
|
||||
{ "sr", "sur" },
|
||||
{ "ss", "ssd" },
|
||||
{ "st", "stp" },
|
||||
{ "sv", "slv" },
|
||||
{ "sy", "syr" },
|
||||
{ "sz", "swz" },
|
||||
//t
|
||||
{ "tc", "tca" },
|
||||
{ "td", "tcd" },
|
||||
{ "tf", "atf" },
|
||||
{ "tg", "tgo" },
|
||||
{ "th", "tha" },
|
||||
{ "tj", "tjk" },
|
||||
{ "tk", "tkl" },
|
||||
{ "tl", "tls" },
|
||||
{ "tm", "tkm" },
|
||||
{ "tn", "tun" },
|
||||
{ "to", "ton" },
|
||||
{ "tr", "tur" },
|
||||
{ "tt", "tto" },
|
||||
{ "tv", "tuv" },
|
||||
{ "tw", "twn" },
|
||||
{ "tz", "tza" },
|
||||
//u
|
||||
{ "ua", "ukr" },
|
||||
{ "ug", "uga" },
|
||||
{ "um", "umi" },
|
||||
{ "us", "usa" },
|
||||
{ "uy", "ury" },
|
||||
{ "uz", "uzb" },
|
||||
//v
|
||||
{ "va", "vat" },
|
||||
{ "vc", "vct" },
|
||||
{ "ve", "ven" },
|
||||
{ "vg", "vgb" },
|
||||
{ "vi", "vir" },
|
||||
{ "vn", "vnm" },
|
||||
{ "vu", "vut" },
|
||||
//w
|
||||
{ "wf", "wlf" },
|
||||
{ "ws", "wsm" },
|
||||
//y
|
||||
{ "ye", "yem" },
|
||||
{ "yt", "myt" },
|
||||
// z
|
||||
{ "za", "zaf" },
|
||||
{ "zm", "zmb" },
|
||||
{ "zw", "zwe" }
|
||||
};
|
||||
|
||||
void kiwix::sleep(unsigned int milliseconds)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
Sleep(milliseconds);
|
||||
#else
|
||||
usleep(1000 * milliseconds);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
struct XmlStringWriter: pugi::xml_writer
|
||||
{
|
||||
std::string result;
|
||||
virtual void write(const void* data, size_t size){
|
||||
result.append(static_cast<const char*>(data), size);
|
||||
}
|
||||
};
|
||||
|
||||
std::string kiwix::nodeToString(pugi::xml_node node)
|
||||
{
|
||||
XmlStringWriter writer;
|
||||
node.print(writer, " ");
|
||||
return writer.result;
|
||||
}
|
||||
|
||||
std::string kiwix::converta2toa3(const std::string& a2code){
|
||||
return codeisomapping.at(a2code);
|
||||
}
|
||||
335
src/common/pathTools.cpp
Normal file
335
src/common/pathTools.cpp
Normal file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Copyright 2011-2014 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <common/pathTools.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <limits.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#elif _WIN32
|
||||
#include <direct.h>
|
||||
#include <windows.h>
|
||||
#include "shlwapi.h"
|
||||
#define getcwd _getcwd // stupid MSFT "deprecation" warning
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
const std::string SEPARATOR("\\");
|
||||
#else
|
||||
const std::string SEPARATOR("/");
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 1024
|
||||
#endif
|
||||
|
||||
bool isRelativePath(const string& path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return path.empty() || path.substr(1, 2) == ":\\" ? false : true;
|
||||
#else
|
||||
return path.empty() || path.substr(0, 1) == "/" ? false : true;
|
||||
#endif
|
||||
}
|
||||
|
||||
string computeRelativePath(const string path, const string absolutePath)
|
||||
{
|
||||
std::vector<std::string> pathParts = kiwix::split(path, SEPARATOR);
|
||||
std::vector<std::string> absolutePathParts
|
||||
= kiwix::split(absolutePath, SEPARATOR);
|
||||
|
||||
unsigned int commonCount = 0;
|
||||
while (commonCount < pathParts.size()
|
||||
&& commonCount < absolutePathParts.size()
|
||||
&& pathParts[commonCount] == absolutePathParts[commonCount]) {
|
||||
commonCount++;
|
||||
}
|
||||
|
||||
string relativePath;
|
||||
#ifdef _WIN32
|
||||
/* On Windows you have a token more because the root is represented
|
||||
by a letter */
|
||||
if (commonCount == 0) {
|
||||
relativePath = ".." + SEPARATOR;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (unsigned int i = commonCount; i < pathParts.size(); i++) {
|
||||
relativePath += ".." + SEPARATOR;
|
||||
}
|
||||
for (unsigned int i = commonCount; i < absolutePathParts.size(); i++) {
|
||||
relativePath += absolutePathParts[i];
|
||||
relativePath += i + 1 < absolutePathParts.size() ? SEPARATOR : "";
|
||||
}
|
||||
return relativePath;
|
||||
}
|
||||
|
||||
/* Warning: the relative path must be with slashes */
|
||||
string computeAbsolutePath(const string path, const string relativePath)
|
||||
{
|
||||
string absolutePath;
|
||||
|
||||
if (path.empty()) {
|
||||
char* path = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
path = _getcwd(path, size);
|
||||
#else
|
||||
path = getcwd(path, size);
|
||||
#endif
|
||||
|
||||
absolutePath = string(path) + SEPARATOR;
|
||||
} else {
|
||||
absolutePath = path.substr(path.length() - 1, 1) == SEPARATOR
|
||||
? path
|
||||
: path + SEPARATOR;
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
char* cRelativePath = _strdup(relativePath.c_str());
|
||||
#else
|
||||
char* cRelativePath = strdup(relativePath.c_str());
|
||||
#endif
|
||||
char* token = strtok(cRelativePath, "/");
|
||||
|
||||
while (token != NULL) {
|
||||
if (string(token) == "..") {
|
||||
absolutePath = removeLastPathElement(absolutePath, true, false);
|
||||
token = strtok(NULL, "/");
|
||||
} else if (strcmp(token, ".") && strcmp(token, "")) {
|
||||
absolutePath += string(token);
|
||||
token = strtok(NULL, "/");
|
||||
if (token != NULL) {
|
||||
absolutePath += SEPARATOR;
|
||||
}
|
||||
} else {
|
||||
token = strtok(NULL, "/");
|
||||
}
|
||||
}
|
||||
|
||||
return absolutePath;
|
||||
}
|
||||
|
||||
string removeLastPathElement(const string path,
|
||||
const bool removePreSeparator,
|
||||
const bool removePostSeparator)
|
||||
{
|
||||
string newPath = path;
|
||||
size_t offset = newPath.find_last_of(SEPARATOR);
|
||||
if (removePreSeparator &&
|
||||
#ifndef _WIN32
|
||||
offset != newPath.find_first_of(SEPARATOR) &&
|
||||
#endif
|
||||
offset == newPath.length() - 1) {
|
||||
newPath = newPath.substr(0, offset);
|
||||
offset = newPath.find_last_of(SEPARATOR);
|
||||
}
|
||||
newPath = removePostSeparator ? newPath.substr(0, offset)
|
||||
: newPath.substr(0, offset + 1);
|
||||
return newPath;
|
||||
}
|
||||
|
||||
string appendToDirectory(const string& directoryPath, const string& filename)
|
||||
{
|
||||
string newPath = directoryPath + SEPARATOR + filename;
|
||||
return newPath;
|
||||
}
|
||||
|
||||
string getLastPathElement(const string& path)
|
||||
{
|
||||
return path.substr(path.find_last_of(SEPARATOR) + 1);
|
||||
}
|
||||
|
||||
unsigned int getFileSize(const string& path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
struct _stat filestatus;
|
||||
_stat(path.c_str(), &filestatus);
|
||||
#else
|
||||
struct stat filestatus;
|
||||
stat(path.c_str(), &filestatus);
|
||||
#endif
|
||||
|
||||
return filestatus.st_size / 1024;
|
||||
}
|
||||
|
||||
string getFileSizeAsString(const string& path)
|
||||
{
|
||||
ostringstream convert;
|
||||
convert << getFileSize(path);
|
||||
return convert.str();
|
||||
}
|
||||
|
||||
string getFileContent(const string& path)
|
||||
{
|
||||
std::ifstream f(path, std::ios::in|std::ios::ate);
|
||||
std::string content;
|
||||
if (f.is_open()) {
|
||||
auto size = f.tellg();
|
||||
content.reserve(size);
|
||||
f.seekg(0, std::ios::beg);
|
||||
content.assign((std::istreambuf_iterator<char>(f)),
|
||||
std::istreambuf_iterator<char>());
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
bool fileExists(const string& path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return PathFileExists(path.c_str());
|
||||
#else
|
||||
bool flag = false;
|
||||
fstream fin;
|
||||
fin.open(path.c_str(), ios::in);
|
||||
if (fin.is_open()) {
|
||||
flag = true;
|
||||
}
|
||||
fin.close();
|
||||
return flag;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool makeDirectory(const string& path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int status = _mkdir(path.c_str());
|
||||
#else
|
||||
int status = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
#endif
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
string makeTmpDirectory()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
char cbase[MAX_PATH+1];
|
||||
int base_len = GetTempPath(MAX_PATH+1, cbase);
|
||||
UUID uuid;
|
||||
UuidCreate(&uuid);
|
||||
char* dir_name;
|
||||
UuidToString(&uuid, reinterpret_cast<unsigned char**>(&dir_name));
|
||||
string dir(cbase, base_len);
|
||||
dir += dir_name;
|
||||
_mkdir(dir.c_str());
|
||||
RpcStringFree(reinterpret_cast<unsigned char**>(&dir_name));
|
||||
#else
|
||||
string base = "/tmp";
|
||||
auto _template = base + "/kiwix-lib_XXXXXX";
|
||||
char* _template_array = new char[_template.size()+1];
|
||||
memcpy(_template_array, _template.c_str(), _template.size());
|
||||
string dir = mkdtemp(_template_array);
|
||||
delete[] _template_array;
|
||||
#endif
|
||||
return dir;
|
||||
}
|
||||
|
||||
/* Try to create a link and if does not work then make a copy */
|
||||
bool copyFile(const string& sourcePath, const string& destPath)
|
||||
{
|
||||
try {
|
||||
#ifndef _WIN32
|
||||
if (link(sourcePath.c_str(), destPath.c_str()) != 0) {
|
||||
#endif
|
||||
std::ifstream infile(sourcePath.c_str(), std::ios_base::binary);
|
||||
std::ofstream outfile(destPath.c_str(), std::ios_base::binary);
|
||||
outfile << infile.rdbuf();
|
||||
#ifndef _WIN32
|
||||
}
|
||||
#endif
|
||||
} catch (exception& e) {
|
||||
cerr << e.what() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string getExecutablePath()
|
||||
{
|
||||
char binRootPath[PATH_MAX];
|
||||
|
||||
#ifdef _WIN32
|
||||
GetModuleFileName(NULL, binRootPath, PATH_MAX);
|
||||
return std::string(binRootPath);
|
||||
#elif __APPLE__
|
||||
uint32_t max = (uint32_t)PATH_MAX;
|
||||
_NSGetExecutablePath(binRootPath, &max);
|
||||
return std::string(binRootPath);
|
||||
#else
|
||||
ssize_t size = readlink("/proc/self/exe", binRootPath, PATH_MAX);
|
||||
if (size != -1) {
|
||||
return std::string(binRootPath, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
bool writeTextFile(const string& path, const string& content)
|
||||
{
|
||||
std::ofstream file;
|
||||
file.open(path.c_str());
|
||||
file << content;
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
string getCurrentDirectory()
|
||||
{
|
||||
char* a_cwd = getcwd(NULL, 0);
|
||||
string s_cwd(a_cwd);
|
||||
free(a_cwd);
|
||||
return s_cwd;
|
||||
}
|
||||
|
||||
string getDataDirectory()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
char* cDataDir = ::getenv("APPDATA");
|
||||
#else
|
||||
char* cDataDir = ::getenv("KIWIX_DATA_DIR");
|
||||
#endif
|
||||
std::string dataDir = cDataDir==nullptr ? "" : cDataDir;
|
||||
if (!dataDir.empty())
|
||||
return dataDir;
|
||||
#ifdef _WIN32
|
||||
cDataDir = ::getenv("USERPROFILE");
|
||||
dataDir = cDataDir==nullptr ? getCurrentDirectory() : cDataDir;
|
||||
#else
|
||||
cDataDir = ::getenv("XDG_DATA_HOME");
|
||||
dataDir = cDataDir==nullptr ? "" : cDataDir;
|
||||
if (dataDir.empty()) {
|
||||
cDataDir = ::getenv("HOME");
|
||||
dataDir = cDataDir==nullptr ? getCurrentDirectory() : cDataDir;
|
||||
dataDir = appendToDirectory(dataDir, ".local");
|
||||
dataDir = appendToDirectory(dataDir, "share");
|
||||
}
|
||||
#endif
|
||||
return appendToDirectory(dataDir, "kiwix");
|
||||
}
|
||||
@@ -17,47 +17,41 @@
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <tools/regexTools.h>
|
||||
#include <common/regexTools.h>
|
||||
|
||||
#include <unicode/regex.h>
|
||||
#include <unicode/ucnv.h>
|
||||
std::map<std::string, icu::RegexMatcher*> regexCache;
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <mutex>
|
||||
|
||||
std::map<std::string, std::shared_ptr<icu::RegexPattern>> regexCache;
|
||||
static std::mutex regexLock;
|
||||
|
||||
std::unique_ptr<icu::RegexMatcher> buildMatcher(const std::string& regex, icu::UnicodeString& content)
|
||||
icu::RegexMatcher* buildRegex(const std::string& regex)
|
||||
{
|
||||
std::shared_ptr<icu::RegexPattern> pattern;
|
||||
icu::RegexMatcher* matcher;
|
||||
auto itr = regexCache.find(regex);
|
||||
|
||||
/* Regex is in cache */
|
||||
try {
|
||||
pattern = regexCache.at(regex);
|
||||
} catch (std::out_of_range&) {
|
||||
// Redo the search with a lock to avoid race condition.
|
||||
std::lock_guard<std::mutex> l(regexLock);
|
||||
try {
|
||||
pattern = regexCache.at(regex);
|
||||
} catch (std::out_of_range&) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
UParseError pe;
|
||||
icu::UnicodeString uregex(regex.c_str());
|
||||
pattern.reset(icu::RegexPattern::compile(uregex, UREGEX_CASE_INSENSITIVE, pe, status));
|
||||
regexCache[regex] = pattern;
|
||||
}
|
||||
if (itr != regexCache.end()) {
|
||||
matcher = itr->second;
|
||||
}
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
return std::unique_ptr<icu::RegexMatcher>(pattern->matcher(content, status));
|
||||
|
||||
/* Regex needs to be parsed (and cached) */
|
||||
else {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
icu::UnicodeString uregex(regex.c_str());
|
||||
matcher = new icu::RegexMatcher(uregex, UREGEX_CASE_INSENSITIVE, status);
|
||||
regexCache[regex] = matcher;
|
||||
}
|
||||
|
||||
return matcher;
|
||||
}
|
||||
|
||||
/* todo */
|
||||
void freeRegexCache()
|
||||
{
|
||||
}
|
||||
bool matchRegex(const std::string& content, const std::string& regex)
|
||||
{
|
||||
ucnv_setDefaultName("UTF-8");
|
||||
icu::UnicodeString ucontent(content.c_str());
|
||||
auto matcher = buildMatcher(regex, ucontent);
|
||||
auto matcher = buildRegex(regex);
|
||||
matcher->reset(ucontent);
|
||||
return matcher->find();
|
||||
}
|
||||
|
||||
@@ -66,12 +60,34 @@ std::string replaceRegex(const std::string& content,
|
||||
const std::string& regex)
|
||||
{
|
||||
ucnv_setDefaultName("UTF-8");
|
||||
icu::UnicodeString ureplacement(replacement.c_str());
|
||||
icu::UnicodeString ucontent(content.c_str());
|
||||
auto matcher = buildMatcher(regex, ucontent);
|
||||
icu::UnicodeString ureplacement(replacement.c_str());
|
||||
auto matcher = buildRegex(regex);
|
||||
matcher->reset(ucontent);
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
auto uresult = matcher->replaceAll(ureplacement, status);
|
||||
std::string tmp;
|
||||
uresult.toUTF8String(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
std::string appendToFirstOccurence(const std::string& content,
|
||||
const std::string regex,
|
||||
const std::string& replacement)
|
||||
{
|
||||
ucnv_setDefaultName("UTF-8");
|
||||
icu::UnicodeString ucontent(content.c_str());
|
||||
icu::UnicodeString ureplacement(replacement.c_str());
|
||||
auto matcher = buildRegex(regex);
|
||||
matcher->reset(ucontent);
|
||||
|
||||
if (matcher->find()) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
ucontent.insert(matcher->end(status), ureplacement);
|
||||
std::string tmp;
|
||||
ucontent.toUTF8String(tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -17,11 +17,8 @@
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Implement function declared in tools.h and tools/stringTools.h
|
||||
#include "tools.h"
|
||||
#include "tools/stringTools.h"
|
||||
#include <common/stringTools.h>
|
||||
|
||||
#include "tools/pathTools.h"
|
||||
#include <unicode/normlzr.h>
|
||||
#include <unicode/rep.h>
|
||||
#include <unicode/translit.h>
|
||||
@@ -29,11 +26,6 @@
|
||||
#include <unicode/uniset.h>
|
||||
#include <unicode/ustring.h>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <regex>
|
||||
|
||||
/* tell ICU where to find its dat file (tables) */
|
||||
void kiwix::loadICUExternalTables()
|
||||
{
|
||||
@@ -44,30 +36,12 @@ void kiwix::loadICUExternalTables()
|
||||
= computeAbsolutePath(executableDirectory, "icudt58l.dat");
|
||||
try {
|
||||
u_setDataDirectory(datPath.c_str());
|
||||
} catch (std::exception& e) {
|
||||
} catch (exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
kiwix::ICULanguageInfo::ICULanguageInfo(const std::string& langCode)
|
||||
: locale(langCode.c_str())
|
||||
{}
|
||||
|
||||
std::string kiwix::ICULanguageInfo::iso3Code() const
|
||||
{
|
||||
return locale.getISO3Language();
|
||||
}
|
||||
|
||||
std::string kiwix::ICULanguageInfo::selfName() const
|
||||
{
|
||||
icu::UnicodeString langSelfNameICUString;
|
||||
locale.getDisplayLanguage(locale, langSelfNameICUString);
|
||||
std::string langSelfName;
|
||||
langSelfNameICUString.toUTF8String(langSelfName);
|
||||
return langSelfName;
|
||||
}
|
||||
|
||||
std::string kiwix::removeAccents(const std::string& text)
|
||||
{
|
||||
loadICUExternalTables();
|
||||
@@ -83,6 +57,8 @@ std::string kiwix::removeAccents(const std::string& text)
|
||||
return unaccentedText;
|
||||
}
|
||||
|
||||
#ifndef __ANDROID__
|
||||
|
||||
/* Prepare integer for display */
|
||||
std::string kiwix::beautifyInteger(uint64_t number)
|
||||
{
|
||||
@@ -162,14 +138,17 @@ std::string kiwix::encodeDiples(const std::string& str)
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
#endif
|
||||
|
||||
/* urlEncode() based on javascript encodeURI() &
|
||||
encodeURIComponent(). Mostly code from rstudio/httpuv (GPLv3) */
|
||||
|
||||
bool isReservedUrlChar(char c)
|
||||
{
|
||||
switch (c) {
|
||||
case ';':
|
||||
case ',':
|
||||
case '/':
|
||||
case '?':
|
||||
case ':':
|
||||
case '@':
|
||||
@@ -177,22 +156,22 @@ bool isReservedUrlChar(char c)
|
||||
case '=':
|
||||
case '+':
|
||||
case '$':
|
||||
case '#':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isHarmlessUriChar(char c)
|
||||
bool needsEscape(char c, bool encodeReserved)
|
||||
{
|
||||
if (c >= 'a' && c <= 'z')
|
||||
return true;
|
||||
return false;
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
return true;
|
||||
return false;
|
||||
if (c >= '0' && c <= '9')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
if (isReservedUrlChar(c))
|
||||
return encodeReserved;
|
||||
switch (c) {
|
||||
case '-':
|
||||
case '_':
|
||||
@@ -203,10 +182,9 @@ bool isHarmlessUriChar(char c)
|
||||
case '\'':
|
||||
case '(':
|
||||
case ')':
|
||||
case '/':
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int hexToInt(char c) {
|
||||
@@ -231,18 +209,18 @@ int hexToInt(char c) {
|
||||
}
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
std::string kiwix::urlEncode(const std::string& value)
|
||||
std::string kiwix::urlEncode(const std::string& value, bool encodeReserved)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << std::hex << std::uppercase;
|
||||
for (const char c : value) {
|
||||
if (isHarmlessUriChar(c)) {
|
||||
os << c;
|
||||
for (std::string::const_iterator it = value.begin();
|
||||
it != value.end();
|
||||
it++) {
|
||||
|
||||
if (!needsEscape(*it, encodeReserved)) {
|
||||
os << *it;
|
||||
} else {
|
||||
const unsigned int charVal = static_cast<unsigned char>(c);
|
||||
os << '%' << std::setw(2) << std::setfill('0') << charVal;
|
||||
os << '%' << std::setw(2) << static_cast<unsigned int>(static_cast<unsigned char>(*it));
|
||||
}
|
||||
}
|
||||
return os.str();
|
||||
@@ -257,7 +235,7 @@ std::string kiwix::urlDecode(const std::string& value, bool component)
|
||||
|
||||
// If there aren't enough characters left for this to be a
|
||||
// valid escape code, just use the character and move on
|
||||
if (value.end() - it < 3) {
|
||||
if (it > value.end() - 3) {
|
||||
os << *it;
|
||||
continue;
|
||||
}
|
||||
@@ -268,15 +246,15 @@ std::string kiwix::urlDecode(const std::string& value, bool component)
|
||||
int iHi = hexToInt(hi);
|
||||
int iLo = hexToInt(lo);
|
||||
if (iHi < 0 || iLo < 0) {
|
||||
// Invalid escape sequence
|
||||
os << '%' << hi << lo;
|
||||
continue;
|
||||
// Invalid escape sequence
|
||||
os << '%' << hi << lo;
|
||||
continue;
|
||||
}
|
||||
char c = (char)(iHi << 4 | iLo);
|
||||
if (!component && isReservedUrlChar(c)) {
|
||||
os << '%' << hi << lo;
|
||||
os << '%' << hi << lo;
|
||||
} else {
|
||||
os << c;
|
||||
os << c;
|
||||
}
|
||||
} else {
|
||||
os << *it;
|
||||
@@ -288,46 +266,36 @@ std::string kiwix::urlDecode(const std::string& value, bool component)
|
||||
|
||||
/* Split string in a token array */
|
||||
std::vector<std::string> kiwix::split(const std::string& str,
|
||||
const std::string& delims,
|
||||
bool dropEmpty,
|
||||
bool keepDelim)
|
||||
const std::string& delims = " *-")
|
||||
{
|
||||
std::string::size_type lastPos = 0;
|
||||
std::string::size_type pos = 0;
|
||||
std::string::size_type lastPos = str.find_first_not_of(delims, 0);
|
||||
std::string::size_type pos = str.find_first_of(delims, lastPos);
|
||||
std::vector<std::string> tokens;
|
||||
while( (pos = str.find_first_of(delims, lastPos)) < str.length() )
|
||||
{
|
||||
auto token = str.substr(lastPos, pos - lastPos);
|
||||
if (!dropEmpty || !token.empty()) {
|
||||
tokens.push_back(token);
|
||||
}
|
||||
if (keepDelim) {
|
||||
tokens.push_back(str.substr(pos, 1));
|
||||
}
|
||||
lastPos = pos + 1;
|
||||
|
||||
while (std::string::npos != pos || std::string::npos != lastPos) {
|
||||
tokens.push_back(str.substr(lastPos, pos - lastPos));
|
||||
lastPos = str.find_first_not_of(delims, pos);
|
||||
pos = str.find_first_of(delims, lastPos);
|
||||
}
|
||||
|
||||
auto token = str.substr(lastPos);
|
||||
if (!dropEmpty || !token.empty()) {
|
||||
tokens.push_back(token);
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
std::string kiwix::join(const std::vector<std::string>& list, const std::string& sep)
|
||||
std::vector<std::string> kiwix::split(const char* lhs, const char* rhs)
|
||||
{
|
||||
std::stringstream ss;
|
||||
bool first = true;
|
||||
for (auto& s:list) {
|
||||
if (!first) {
|
||||
ss << sep;
|
||||
}
|
||||
first = false;
|
||||
ss << s;
|
||||
}
|
||||
return ss.str();
|
||||
const std::string m1(lhs), m2(rhs);
|
||||
return split(m1, m2);
|
||||
}
|
||||
|
||||
std::vector<std::string> kiwix::split(const char* lhs, const std::string& rhs)
|
||||
{
|
||||
return split(lhs, rhs.c_str());
|
||||
}
|
||||
|
||||
std::vector<std::string> kiwix::split(const std::string& lhs, const char* rhs)
|
||||
{
|
||||
return split(lhs.c_str(), rhs);
|
||||
}
|
||||
|
||||
std::string kiwix::ucFirst(const std::string& word)
|
||||
{
|
||||
@@ -408,45 +376,3 @@ std::string kiwix::normalize(const std::string& word)
|
||||
{
|
||||
return kiwix::lcAll(word);
|
||||
}
|
||||
|
||||
|
||||
bool kiwix::startsWith(const std::string& base, const std::string& start)
|
||||
{
|
||||
return start.length() <= base.length()
|
||||
&& std::equal(start.begin(), start.end(), base.begin());
|
||||
}
|
||||
|
||||
std::string kiwix::stripSuffix(const std::string& str, const std::string& suffix)
|
||||
{
|
||||
if (str.size() > suffix.size()) {
|
||||
const auto subStr = str.substr(str.size() - suffix.size(), str.size());
|
||||
if (subStr == suffix) {
|
||||
return str.substr(0, str.size() - suffix.size());
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::vector<std::string> kiwix::getTitleVariants(const std::string& title) {
|
||||
std::vector<std::string> variants;
|
||||
variants.push_back(title);
|
||||
variants.push_back(kiwix::ucFirst(title));
|
||||
variants.push_back(kiwix::lcFirst(title));
|
||||
variants.push_back(kiwix::toTitle(title));
|
||||
return variants;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string kiwix::extractFromString(const std::string& str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string kiwix::getSlugifiedFileName(const std::string& filename)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const std::regex reservedCharsReg(R"([<>:"/\\|?*])");
|
||||
#else
|
||||
const std::regex reservedCharsReg("/");
|
||||
#endif
|
||||
return std::regex_replace(filename, reservedCharsReg, "_");
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
#mesondefine LIBKIWIX_VERSION
|
||||
#mesondefine VERSION
|
||||
|
||||
#mesondefine ENABLE_CTPP2
|
||||
|
||||
210
src/ctpp2/CTPP2VMStringLoader.cpp
Normal file
210
src/ctpp2/CTPP2VMStringLoader.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2013 Renaud Gaudin <reg@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <ctpp2/CTPP2VMStringLoader.hpp>
|
||||
|
||||
namespace CTPP // C++ Template Engine
|
||||
{
|
||||
|
||||
//
|
||||
// Convert byte order
|
||||
//
|
||||
static void ConvertExecutable(VMExecutable * oCore)
|
||||
{
|
||||
// Code entry point
|
||||
oCore -> entry_point = Swap32(oCore -> entry_point);
|
||||
// Offset of code segment
|
||||
oCore -> code_offset = Swap32(oCore -> code_offset);
|
||||
|
||||
// Code segment size
|
||||
oCore -> code_size = Swap32(oCore -> code_size);
|
||||
|
||||
// Offset of static text segment
|
||||
oCore -> syscalls_offset = Swap32(oCore -> syscalls_offset);
|
||||
// Static text segment size
|
||||
oCore -> syscalls_data_size = Swap32(oCore -> syscalls_data_size);
|
||||
|
||||
// Offset of static text index segment
|
||||
oCore -> syscalls_index_offset = Swap32(oCore -> syscalls_index_offset);
|
||||
// Static text index segment size
|
||||
oCore -> syscalls_index_size = Swap32(oCore -> syscalls_index_size);
|
||||
|
||||
// Offset of static data segment
|
||||
oCore -> static_data_offset = Swap32(oCore -> static_data_offset);
|
||||
|
||||
// Static data segment size
|
||||
oCore -> static_data_data_size = Swap32(oCore -> static_data_data_size);
|
||||
|
||||
// Offset of static text segment
|
||||
oCore -> static_text_offset = Swap32(oCore -> static_text_offset);
|
||||
// Static text segment size
|
||||
oCore -> static_text_data_size = Swap32(oCore -> static_text_data_size);
|
||||
|
||||
// Offset of static text index segment
|
||||
oCore -> static_text_index_offset = Swap32(oCore -> static_text_index_offset);
|
||||
// Static text index segment size
|
||||
oCore -> static_text_index_size = Swap32(oCore -> static_text_index_size);
|
||||
|
||||
// Version 2.2+
|
||||
// Offset of static data bit index
|
||||
oCore -> static_data_bit_index_offset = Swap32(oCore -> static_data_bit_index_offset);
|
||||
/// Offset of static data bit index
|
||||
oCore -> static_data_bit_index_size = Swap32(oCore -> static_data_bit_index_size);
|
||||
|
||||
// Platform
|
||||
oCore -> platform = Swap64(oCore -> platform);
|
||||
|
||||
// Ugly-jolly hack!
|
||||
// ... dereferencing type-punned pointer will break strict-aliasing rules ...
|
||||
UINT_64 iTMP;
|
||||
memcpy(&iTMP, &(oCore -> ieee754double), sizeof(UINT_64));
|
||||
iTMP = Swap64(iTMP);
|
||||
memcpy(&(oCore -> ieee754double), &iTMP, sizeof(UINT_64));
|
||||
|
||||
// Cyclic Redundancy Check
|
||||
oCore -> crc = 0;
|
||||
|
||||
// Convert data structures
|
||||
|
||||
// Convert code segment
|
||||
VMInstruction * pInstructions = const_cast<VMInstruction *>(VMExecutable::GetCodeSeg(oCore));
|
||||
UINT_32 iI = 0;
|
||||
UINT_32 iSteps = oCore -> code_size / sizeof(VMInstruction);
|
||||
for(iI = 0; iI < iSteps; ++iI)
|
||||
{
|
||||
pInstructions -> instruction = Swap32(pInstructions -> instruction);
|
||||
pInstructions -> argument = Swap32(pInstructions -> argument);
|
||||
pInstructions -> reserved = Swap64(pInstructions -> reserved);
|
||||
++pInstructions;
|
||||
}
|
||||
|
||||
// Convert syscalls index
|
||||
TextDataIndex * pTextIndex = const_cast<TextDataIndex *>(VMExecutable::GetSyscallsIndexSeg(oCore));
|
||||
iSteps = oCore -> syscalls_index_size / sizeof(TextDataIndex);
|
||||
for(iI = 0; iI < iSteps; ++iI)
|
||||
{
|
||||
pTextIndex -> offset = Swap32(pTextIndex -> offset);
|
||||
pTextIndex -> length = Swap32(pTextIndex -> length);
|
||||
++pTextIndex;
|
||||
}
|
||||
|
||||
// Convert static text index
|
||||
pTextIndex = const_cast<TextDataIndex *>(VMExecutable::GetStaticTextIndexSeg(oCore));
|
||||
iSteps = oCore -> static_text_index_size / sizeof(TextDataIndex);
|
||||
for(iI = 0; iI < iSteps; ++iI)
|
||||
{
|
||||
pTextIndex -> offset = Swap32(pTextIndex -> offset);
|
||||
pTextIndex -> length = Swap32(pTextIndex -> length);
|
||||
++pTextIndex;
|
||||
}
|
||||
|
||||
// Convert static data
|
||||
StaticDataVar * pStaticDataVar = const_cast<StaticDataVar *>(VMExecutable::GetStaticDataSeg(oCore));
|
||||
iSteps = oCore -> static_data_data_size / sizeof(StaticDataVar);
|
||||
for(iI = 0; iI < iSteps; ++iI)
|
||||
{
|
||||
(*pStaticDataVar).i_data = Swap64((*pStaticDataVar).i_data);
|
||||
++pStaticDataVar;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
VMStringLoader::VMStringLoader(CCHAR_P rawContent, size_t rawContentSize)
|
||||
{
|
||||
oCore = (VMExecutable *)malloc(rawContentSize + 1);
|
||||
memcpy(oCore, rawContent, rawContentSize);
|
||||
|
||||
if (oCore -> magic[0] == 'C' &&
|
||||
oCore -> magic[1] == 'T' &&
|
||||
oCore -> magic[2] == 'P' &&
|
||||
oCore -> magic[3] == 'P')
|
||||
{
|
||||
// Check version
|
||||
if (oCore -> version[0] >= 1)
|
||||
{
|
||||
// Platform-dependent data (byte order)
|
||||
if (oCore -> platform == 0x4142434445464748ull)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
fprintf(stderr, "Big/Little Endian conversion: Nothing to do\n");
|
||||
#endif
|
||||
|
||||
// Nothing to do, only check crc
|
||||
UINT_32 iCRC = oCore -> crc;
|
||||
oCore -> crc = 0;
|
||||
|
||||
// Calculate CRC of file
|
||||
// KELSON: next line used to refer to oStat.st_size
|
||||
// changed it to rawContentSize
|
||||
if (iCRC != crc32((UCCHAR_P)oCore, rawContentSize))
|
||||
{
|
||||
free(oCore);
|
||||
throw CTPPLogicError("CRC checksum invalid");
|
||||
}
|
||||
}
|
||||
// Platform-dependent data (byte order)
|
||||
else if (oCore -> platform == 0x4847464544434241ull)
|
||||
{
|
||||
// Need to reconvert data
|
||||
#ifdef _DEBUG
|
||||
fprintf(stderr, "Big/Little Endian conversion: Need to reconvert core\n");
|
||||
#endif
|
||||
ConvertExecutable(oCore);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(oCore);
|
||||
throw CTPPLogicError("Conversion of middle-end architecture does not supported.");
|
||||
}
|
||||
|
||||
// Check IEEE 754 format
|
||||
if (oCore -> ieee754double != 15839800103804824402926068484019465486336.0)
|
||||
{
|
||||
free(oCore);
|
||||
throw CTPPLogicError("IEEE 754 format is broken, cannot convert file");
|
||||
}
|
||||
}
|
||||
|
||||
pVMMemoryCore = new VMMemoryCore(oCore);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(oCore);
|
||||
throw CTPPLogicError("Not an CTPP bytecode file.");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Get ready-to-run program
|
||||
//
|
||||
const VMMemoryCore * VMStringLoader::GetCore() const { return pVMMemoryCore; }
|
||||
|
||||
//
|
||||
// A destructor
|
||||
//
|
||||
VMStringLoader::~VMStringLoader() throw()
|
||||
{
|
||||
delete pVMMemoryCore;
|
||||
free(oCore);
|
||||
}
|
||||
|
||||
} // namespace CTPP
|
||||
// End.
|
||||
@@ -18,9 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "downloader.h"
|
||||
#include "tools.h"
|
||||
#include "tools/pathTools.h"
|
||||
#include "tools/stringTools.h"
|
||||
#include "common/pathTools.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
@@ -30,7 +28,7 @@
|
||||
|
||||
#include "aria2.h"
|
||||
#include "xmlrpc.h"
|
||||
#include "tools/otherTools.h"
|
||||
#include "common/otherTools.h"
|
||||
#include <pugixml.hpp>
|
||||
|
||||
namespace kiwix
|
||||
@@ -38,8 +36,6 @@ namespace kiwix
|
||||
|
||||
void Download::updateStatus(bool follow)
|
||||
{
|
||||
if (m_status == Download::K_REMOVED)
|
||||
return;
|
||||
static std::vector<std::string> statusKey = {"status", "files", "totalLength",
|
||||
"completedLength", "followedBy",
|
||||
"downloadSpeed", "verifiedLength"};
|
||||
@@ -97,78 +93,28 @@ void Download::updateStatus(bool follow)
|
||||
}
|
||||
}
|
||||
|
||||
void Download::resumeDownload()
|
||||
{
|
||||
if (!m_followedBy.empty())
|
||||
mp_aria->unpause(m_followedBy);
|
||||
else
|
||||
mp_aria->unpause(m_did);
|
||||
updateStatus(true);
|
||||
}
|
||||
|
||||
void Download::pauseDownload()
|
||||
{
|
||||
if (!m_followedBy.empty())
|
||||
mp_aria->pause(m_followedBy);
|
||||
else
|
||||
mp_aria->pause(m_did);
|
||||
updateStatus(true);
|
||||
}
|
||||
|
||||
void Download::cancelDownload()
|
||||
{
|
||||
if (!m_followedBy.empty())
|
||||
mp_aria->remove(m_followedBy);
|
||||
else
|
||||
mp_aria->remove(m_did);
|
||||
m_status = Download::K_REMOVED;
|
||||
}
|
||||
|
||||
/* Constructor */
|
||||
Downloader::Downloader(std::string sessionFileDir) :
|
||||
mp_aria(new Aria2(sessionFileDir))
|
||||
Downloader::Downloader() :
|
||||
mp_aria(new Aria2())
|
||||
{
|
||||
try {
|
||||
for (auto gid : mp_aria->tellWaiting()) {
|
||||
m_knownDownloads[gid] = std::unique_ptr<Download>(new Download(mp_aria, gid));
|
||||
m_knownDownloads[gid]->updateStatus(false);
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << "aria2 tellWaiting failed : " << e.what() << std::endl;
|
||||
}
|
||||
try {
|
||||
for (auto gid : mp_aria->tellActive()) {
|
||||
if( m_knownDownloads.find(gid) == m_knownDownloads.end()) {
|
||||
m_knownDownloads[gid] = std::unique_ptr<Download>(new Download(mp_aria, gid));
|
||||
m_knownDownloads[gid]->updateStatus(false);
|
||||
}
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << "aria2 tellActive failed : " << e.what() << std::endl;
|
||||
for (auto gid : mp_aria->tellActive()) {
|
||||
m_knownDownloads[gid] = std::unique_ptr<Download>(new Download(mp_aria, gid));
|
||||
m_knownDownloads[gid]->updateStatus();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Destructor */
|
||||
Downloader::~Downloader()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void Downloader::close()
|
||||
{
|
||||
if ( mp_aria ) {
|
||||
try {
|
||||
mp_aria->close();
|
||||
} catch (const std::exception& err) {
|
||||
std::cerr << "ERROR: Failed to save the downloader state: "
|
||||
<< err.what() << std::endl;
|
||||
}
|
||||
mp_aria.reset();
|
||||
}
|
||||
mp_aria->close();
|
||||
}
|
||||
|
||||
std::vector<std::string> Downloader::getDownloadIds() const {
|
||||
std::unique_lock<std::mutex> lock(m_lock);
|
||||
std::vector<std::string> Downloader::getDownloadIds() {
|
||||
std::vector<std::string> ret;
|
||||
for(auto& p:m_knownDownloads) {
|
||||
ret.push_back(p.first);
|
||||
@@ -176,82 +122,33 @@ std::vector<std::string> Downloader::getDownloadIds() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
namespace
|
||||
Download* Downloader::startDownload(const std::string& uri)
|
||||
{
|
||||
|
||||
bool downloadCanBeReused(const Download& d,
|
||||
const std::string& uri,
|
||||
const Downloader::Options& /*options*/)
|
||||
{
|
||||
const auto& uris = d.getUris();
|
||||
const bool sameURI = std::find(uris.begin(), uris.end(), uri) != uris.end();
|
||||
|
||||
if ( !sameURI )
|
||||
return false;
|
||||
|
||||
switch ( d.getStatus() ) {
|
||||
case Download::K_ERROR:
|
||||
case Download::K_UNKNOWN:
|
||||
case Download::K_REMOVED:
|
||||
return false;
|
||||
|
||||
case Download::K_ACTIVE:
|
||||
case Download::K_WAITING:
|
||||
case Download::K_PAUSED:
|
||||
return true; // XXX: what if options are different?
|
||||
|
||||
case Download::K_COMPLETE:
|
||||
return fileExists(d.getPath()); // XXX: what if options are different?
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
std::shared_ptr<Download> Downloader::startDownload(const std::string& uri, const std::string& downloadDir, Options options)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_lock);
|
||||
options.erase(std::remove_if(options.begin(), options.end(), [](const auto& option) {
|
||||
return option.first == "dir";
|
||||
}), options.end());
|
||||
options.push_back({"dir", downloadDir});
|
||||
for (auto& p: m_knownDownloads) {
|
||||
auto& d = p.second;
|
||||
if ( downloadCanBeReused(*d, uri, options) )
|
||||
return d;
|
||||
auto& uris = d->getUris();
|
||||
if (std::find(uris.begin(), uris.end(), uri) != uris.end())
|
||||
return d.get();
|
||||
}
|
||||
std::vector<std::string> uris = {uri};
|
||||
auto gid = mp_aria->addUri(uris, options);
|
||||
m_knownDownloads[gid] = std::make_shared<Download>(mp_aria, gid);
|
||||
return m_knownDownloads[gid];
|
||||
auto gid = mp_aria->addUri(uris);
|
||||
m_knownDownloads[gid] = std::unique_ptr<Download>(new Download(mp_aria, gid));
|
||||
return m_knownDownloads[gid].get();
|
||||
}
|
||||
|
||||
std::shared_ptr<Download> Downloader::getDownload(const std::string& did)
|
||||
Download* Downloader::getDownload(const std::string& did)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_lock);
|
||||
try {
|
||||
return m_knownDownloads.at(did);
|
||||
} catch(std::exception& e) {
|
||||
for (auto gid : mp_aria->tellWaiting()) {
|
||||
if (gid == did) {
|
||||
m_knownDownloads[gid] = std::make_shared<Download>(mp_aria, gid);
|
||||
return m_knownDownloads[gid];
|
||||
}
|
||||
}
|
||||
return m_knownDownloads.at(did).get();
|
||||
} catch(exception& e) {
|
||||
for (auto gid : mp_aria->tellActive()) {
|
||||
if (gid == did) {
|
||||
m_knownDownloads[gid] = std::make_shared<Download>(mp_aria, gid);
|
||||
return m_knownDownloads[gid];
|
||||
m_knownDownloads[gid] = std::unique_ptr<Download>(new Download(mp_aria, gid));
|
||||
return m_knownDownloads[gid].get();
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
size_t Downloader::getNbDownload() const {
|
||||
std::unique_lock<std::mutex> lock(m_lock);
|
||||
return m_knownDownloads.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
138
src/entry.cpp
Normal file
138
src/entry.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2011 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "reader.h"
|
||||
#include <time.h>
|
||||
|
||||
#include <zim/search.h>
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
Entry::Entry(zim::Article article)
|
||||
: article(article)
|
||||
{
|
||||
}
|
||||
|
||||
#define RETURN_IF_INVALID(WHAT) if(!good()) { return (WHAT); }
|
||||
|
||||
std::string Entry::getPath() const
|
||||
{
|
||||
RETURN_IF_INVALID("");
|
||||
return article.getLongUrl();
|
||||
}
|
||||
|
||||
std::string Entry::getTitle() const
|
||||
{
|
||||
RETURN_IF_INVALID("");
|
||||
return article.getTitle();
|
||||
}
|
||||
|
||||
std::string Entry::getContent() const
|
||||
{
|
||||
RETURN_IF_INVALID("");
|
||||
return article.getData();
|
||||
}
|
||||
|
||||
zim::Blob Entry::getBlob(offset_type offset) const
|
||||
{
|
||||
RETURN_IF_INVALID(zim::Blob());
|
||||
return article.getData(offset);
|
||||
}
|
||||
|
||||
zim::Blob Entry::getBlob(offset_type offset, size_type size) const
|
||||
{
|
||||
RETURN_IF_INVALID(zim::Blob());
|
||||
return article.getData(offset, size);
|
||||
}
|
||||
|
||||
std::pair<std::string, offset_type> Entry::getDirectAccessInfo() const
|
||||
{
|
||||
RETURN_IF_INVALID(std::make_pair("", 0));
|
||||
return article.getDirectAccessInformation();
|
||||
}
|
||||
|
||||
size_type Entry::getSize() const
|
||||
{
|
||||
RETURN_IF_INVALID(0);
|
||||
return article.getArticleSize();
|
||||
}
|
||||
|
||||
std::string Entry::getMimetype() const
|
||||
{
|
||||
RETURN_IF_INVALID("");
|
||||
try {
|
||||
return article.getMimeType();
|
||||
} catch (exception& e) {
|
||||
return "application/octet-stream";
|
||||
}
|
||||
}
|
||||
|
||||
bool Entry::isRedirect() const
|
||||
{
|
||||
RETURN_IF_INVALID(false);
|
||||
return article.isRedirect();
|
||||
}
|
||||
|
||||
bool Entry::isLinkTarget() const
|
||||
{
|
||||
RETURN_IF_INVALID(false);
|
||||
return article.isLinktarget();
|
||||
}
|
||||
|
||||
bool Entry::isDeleted() const
|
||||
{
|
||||
RETURN_IF_INVALID(false);
|
||||
return article.isDeleted();
|
||||
}
|
||||
|
||||
Entry Entry::getRedirectEntry() const
|
||||
{
|
||||
RETURN_IF_INVALID(Entry());
|
||||
if ( !article.isRedirect() ) {
|
||||
throw NoEntry();
|
||||
}
|
||||
|
||||
auto targeted_article = article.getRedirectArticle();
|
||||
if ( !targeted_article.good()) {
|
||||
throw NoEntry();
|
||||
}
|
||||
return targeted_article;
|
||||
}
|
||||
|
||||
Entry Entry::getFinalEntry() const
|
||||
{
|
||||
RETURN_IF_INVALID(Entry());
|
||||
if (final_article.good()) {
|
||||
return final_article;
|
||||
}
|
||||
|
||||
int loopCounter = 42;
|
||||
final_article = article;
|
||||
while (final_article.isRedirect() && loopCounter--) {
|
||||
final_article = final_article.getRedirectArticle();
|
||||
if ( !final_article.good()) {
|
||||
throw NoEntry();
|
||||
}
|
||||
}
|
||||
|
||||
return final_article;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
#include "html_dumper.h"
|
||||
#include "libkiwix-resources.h"
|
||||
#include "tools/otherTools.h"
|
||||
#include "tools.h"
|
||||
#include "tools/regexTools.h"
|
||||
#include "server/i18n_utils.h"
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
/* Constructor */
|
||||
HTMLDumper::HTMLDumper(const Library* library, const NameMapper* nameMapper)
|
||||
: LibraryDumper(library, nameMapper)
|
||||
{
|
||||
}
|
||||
/* Destructor */
|
||||
HTMLDumper::~HTMLDumper()
|
||||
{
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::string humanFriendlyTitle(std::string title)
|
||||
{
|
||||
std::string humanFriendlyString = replaceRegex(title, "_", " ");
|
||||
humanFriendlyString[0] = toupper(humanFriendlyString[0]);
|
||||
return humanFriendlyString;
|
||||
}
|
||||
|
||||
kainjow::mustache::object getLangTag(const std::vector<std::string>& bookLanguages) {
|
||||
std::string langShortString = "";
|
||||
std::string langFullString = "???";
|
||||
|
||||
//if more than 1 languages then show "mul" else show the language
|
||||
if(bookLanguages.size() > 1) {
|
||||
std::vector<std::string> mulLanguages;
|
||||
langShortString = "mul";
|
||||
for (const auto& lang : bookLanguages) {
|
||||
const std::string fullLang = getLanguageSelfName(lang);
|
||||
mulLanguages.push_back(fullLang);
|
||||
}
|
||||
langFullString = kiwix::join(mulLanguages, ",");
|
||||
} else if(bookLanguages.size() == 1) {
|
||||
langShortString = bookLanguages[0];
|
||||
langFullString = getLanguageSelfName(langShortString);
|
||||
}
|
||||
|
||||
kainjow::mustache::object langTag;
|
||||
langTag["langShortString"] = langShortString;
|
||||
langTag["langFullString"] = langFullString;
|
||||
return langTag;
|
||||
}
|
||||
|
||||
kainjow::mustache::list getTagList(std::string tags)
|
||||
{
|
||||
const auto tagsList = kiwix::split(tags, ";", true, false);
|
||||
kainjow::mustache::list finalTagList;
|
||||
for (auto tag : tagsList) {
|
||||
if (tag[0] != '_')
|
||||
finalTagList.push_back(kainjow::mustache::object{
|
||||
{"tag", tag}
|
||||
});
|
||||
}
|
||||
return finalTagList;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
std::string HTMLDumper::dumpPlainHTML(kiwix::Filter filter) const
|
||||
{
|
||||
kainjow::mustache::list booksData;
|
||||
const auto filteredBooks = library->filter(filter);
|
||||
const auto searchQuery = filter.getQuery();
|
||||
auto languages = getLanguageData();
|
||||
auto categories = getCategoryData();
|
||||
|
||||
for (auto &category : categories) {
|
||||
const auto categoryName = category.get("name")->string_value();
|
||||
if (categoryName == filter.getCategory()) {
|
||||
category["selected"] = true;
|
||||
}
|
||||
category["hf_name"] = humanFriendlyTitle(categoryName);
|
||||
}
|
||||
|
||||
for (auto &language : languages) {
|
||||
if (language.get("lang_code")->string_value() == filter.getLang()) {
|
||||
language["selected"] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for ( const auto& bookId : filteredBooks ) {
|
||||
const auto bookObj = library->getBookById(bookId);
|
||||
const auto bookTitle = bookObj.getTitle();
|
||||
std::string contentId = "";
|
||||
try {
|
||||
contentId = urlEncode(nameMapper->getNameForId(bookId));
|
||||
} catch (...) {}
|
||||
const auto bookDescription = bookObj.getDescription();
|
||||
const auto bookIconUrl = rootLocation + "/catalog/v2/illustration/" + bookId + "/?size=48";
|
||||
const auto tags = bookObj.getTags();
|
||||
const auto downloadAvailable = (bookObj.getUrl() != "");
|
||||
const auto langTagObj = getLangTag(bookObj.getLanguages());
|
||||
std::string faviconAttr = "style=background-image:url(" + bookIconUrl + ")";
|
||||
booksData.push_back(kainjow::mustache::object{
|
||||
{"id", contentId},
|
||||
{"title", bookTitle},
|
||||
{"description", bookDescription},
|
||||
{"langTag", langTagObj},
|
||||
{"faviconAttr", faviconAttr},
|
||||
{"tagList", getTagList(tags)},
|
||||
{"downloadAvailable", downloadAvailable}
|
||||
});
|
||||
}
|
||||
|
||||
auto getTranslation = i18n::GetTranslatedStringWithMsgId(m_userLang);
|
||||
|
||||
const auto translations = kainjow::mustache::object{
|
||||
getTranslation("search"),
|
||||
getTranslation("download"),
|
||||
getTranslation("count-of-matching-books", {{"COUNT", to_string(filteredBooks.size())}}),
|
||||
getTranslation("book-filtering-all-categories"),
|
||||
getTranslation("book-filtering-all-languages"),
|
||||
getTranslation("powered-by-kiwix-html"),
|
||||
getTranslation("welcome-to-kiwix-server"),
|
||||
getTranslation("preview-book"),
|
||||
getTranslation("welcome-page-overzealous-filter", {{"URL", "?lang="}})
|
||||
};
|
||||
|
||||
return render_template(
|
||||
RESOURCE::templates::no_js_library_page_html,
|
||||
kainjow::mustache::object{
|
||||
{"root", rootLocation},
|
||||
{"contentAccessUrl", onlyAsNonEmptyMustacheValue(contentAccessUrl)},
|
||||
{"books", booksData },
|
||||
{"searchQuery", searchQuery},
|
||||
{"languages", languages},
|
||||
{"categories", categories},
|
||||
{"noResults", filteredBooks.size() == 0},
|
||||
{"translations", translations}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace kiwix
|
||||
@@ -1,82 +0,0 @@
|
||||
#include "kiwixserve.h"
|
||||
#include "subprocess.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# define KIWIXSERVE_CMD "kiwix-serve.exe"
|
||||
# include <windows.h>
|
||||
#else
|
||||
# define KIWIXSERVE_CMD "kiwix-serve"
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "tools.h"
|
||||
#include "tools/pathTools.h"
|
||||
#include "tools/stringTools.h"
|
||||
|
||||
namespace kiwix {
|
||||
|
||||
KiwixServe::KiwixServe(const std::string& libraryPath, int port)
|
||||
: m_port(port),
|
||||
m_libraryPath(libraryPath)
|
||||
{
|
||||
}
|
||||
|
||||
KiwixServe::~KiwixServe()
|
||||
{
|
||||
shutDown();
|
||||
}
|
||||
|
||||
void KiwixServe::run()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int pid = GetCurrentProcessId();
|
||||
#else
|
||||
pid_t pid = getpid();
|
||||
|
||||
#endif
|
||||
|
||||
std::vector<const char*> callCmd;
|
||||
std::string kiwixServeCmd = appendToDirectory(
|
||||
removeLastPathElement(getExecutablePath(true)),
|
||||
KIWIXSERVE_CMD);
|
||||
if (fileExists(kiwixServeCmd)) {
|
||||
// A local kiwix-serve exe exists (packaged with kiwix-desktop), use it.
|
||||
callCmd.push_back(kiwixServeCmd.c_str());
|
||||
} else {
|
||||
// Try to use a potential installed kiwix-serve.
|
||||
callCmd.push_back(KIWIXSERVE_CMD);
|
||||
}
|
||||
std::string attachProcessOpt = "-a" + to_string(pid);
|
||||
std::string portOpt = "-p" + to_string(m_port);
|
||||
callCmd.push_back(attachProcessOpt.c_str());
|
||||
callCmd.push_back(portOpt.c_str());
|
||||
callCmd.push_back("-l");
|
||||
callCmd.push_back(m_libraryPath.c_str());
|
||||
mp_kiwixServe = Subprocess::run(callCmd);
|
||||
}
|
||||
|
||||
void KiwixServe::shutDown()
|
||||
{
|
||||
if (mp_kiwixServe)
|
||||
mp_kiwixServe->kill();
|
||||
}
|
||||
|
||||
bool KiwixServe::isRunning()
|
||||
{
|
||||
if (mp_kiwixServe) {
|
||||
return (mp_kiwixServe->isRunning());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int KiwixServe::setPort(int port)
|
||||
{
|
||||
if (port >= 1 && port <= 65535) {
|
||||
m_port = port;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return m_port;
|
||||
}
|
||||
|
||||
}
|
||||
1150
src/library.cpp
1150
src/library.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,61 +0,0 @@
|
||||
#include "library_dumper.h"
|
||||
#include "tools/stringTools.h"
|
||||
#include "tools/otherTools.h"
|
||||
#include "tools.h"
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
/* Constructor */
|
||||
LibraryDumper::LibraryDumper(const Library* library, const NameMapper* nameMapper)
|
||||
: library(library),
|
||||
nameMapper(nameMapper)
|
||||
{
|
||||
}
|
||||
/* Destructor */
|
||||
LibraryDumper::~LibraryDumper()
|
||||
{
|
||||
}
|
||||
|
||||
void LibraryDumper::setOpenSearchInfo(int totalResults, int startIndex, int count)
|
||||
{
|
||||
m_totalResults = totalResults;
|
||||
m_startIndex = startIndex,
|
||||
m_count = count;
|
||||
}
|
||||
|
||||
kainjow::mustache::list LibraryDumper::getCategoryData() const
|
||||
{
|
||||
const auto now = gen_date_str();
|
||||
kainjow::mustache::list categoryData;
|
||||
for ( const auto& category : library->getBooksCategories() ) {
|
||||
const auto urlencodedCategoryName = urlEncode(category);
|
||||
categoryData.push_back(kainjow::mustache::object{
|
||||
{"name", category},
|
||||
{"urlencoded_name", urlencodedCategoryName},
|
||||
{"updated", now},
|
||||
{"id", gen_uuid(libraryId + "/categories/" + urlencodedCategoryName)}
|
||||
});
|
||||
}
|
||||
return categoryData;
|
||||
}
|
||||
|
||||
kainjow::mustache::list LibraryDumper::getLanguageData() const
|
||||
{
|
||||
const auto now = gen_date_str();
|
||||
kainjow::mustache::list languageData;
|
||||
for ( const auto& langAndBookCount : library->getBooksLanguagesWithCounts() ) {
|
||||
const std::string languageCode = langAndBookCount.first;
|
||||
const int bookCount = langAndBookCount.second;
|
||||
const auto languageSelfName = getLanguageSelfName(languageCode);
|
||||
languageData.push_back(kainjow::mustache::object{
|
||||
{"lang_code", languageCode},
|
||||
{"lang_self_name", languageSelfName},
|
||||
{"book_count", to_string(bookCount)},
|
||||
{"updated", now},
|
||||
{"id", gen_uuid(libraryId + "/languages/" + languageCode)}
|
||||
});
|
||||
}
|
||||
return languageData;
|
||||
}
|
||||
|
||||
} // namespace kiwix
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "libxml_dumper.h"
|
||||
#include "book.h"
|
||||
|
||||
#include "tools.h"
|
||||
#include "tools/base64.h"
|
||||
#include "tools/stringTools.h"
|
||||
#include "tools/otherTools.h"
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
/* Constructor */
|
||||
LibXMLDumper::LibXMLDumper(const Library* library)
|
||||
: library(library)
|
||||
{
|
||||
}
|
||||
/* Destructor */
|
||||
LibXMLDumper::~LibXMLDumper()
|
||||
{
|
||||
}
|
||||
|
||||
#define ADD_ATTRIBUTE(node, name, value) { (node).append_attribute((name)) = (value).c_str(); }
|
||||
#define ADD_ATTR_NOT_EMPTY(node, name, value) { if (!(value).empty()) ADD_ATTRIBUTE(node, name, value); }
|
||||
|
||||
void LibXMLDumper::handleBook(Book book, pugi::xml_node root_node) {
|
||||
if (book.readOnly())
|
||||
return;
|
||||
|
||||
auto entry_node = root_node.append_child("book");
|
||||
ADD_ATTRIBUTE(entry_node, "id", book.getId());
|
||||
|
||||
if (!book.getPath().empty()) {
|
||||
ADD_ATTRIBUTE(entry_node, "path", computeRelativePath(baseDir, book.getPath()));
|
||||
}
|
||||
|
||||
if (book.getOrigId().empty()) {
|
||||
ADD_ATTR_NOT_EMPTY(entry_node, "title", book.getTitle());
|
||||
ADD_ATTR_NOT_EMPTY(entry_node, "description", book.getDescription());
|
||||
ADD_ATTR_NOT_EMPTY(entry_node, "language", book.getCommaSeparatedLanguages());
|
||||
ADD_ATTR_NOT_EMPTY(entry_node, "creator", book.getCreator());
|
||||
ADD_ATTR_NOT_EMPTY(entry_node, "publisher", book.getPublisher());
|
||||
ADD_ATTR_NOT_EMPTY(entry_node, "name", book.getName());
|
||||
ADD_ATTR_NOT_EMPTY(entry_node, "flavour", book.getFlavour());
|
||||
ADD_ATTR_NOT_EMPTY(entry_node, "tags", book.getTags());
|
||||
try {
|
||||
auto defaultIllustration = book.getIllustration(48);
|
||||
ADD_ATTR_NOT_EMPTY(entry_node, "faviconMimeType", defaultIllustration->mimeType);
|
||||
ADD_ATTR_NOT_EMPTY(entry_node, "faviconUrl", defaultIllustration->url);
|
||||
if (!defaultIllustration->getData().empty())
|
||||
ADD_ATTRIBUTE(entry_node, "favicon", base64_encode(defaultIllustration->getData()));
|
||||
} catch(...) {}
|
||||
} else {
|
||||
ADD_ATTRIBUTE(entry_node, "origId", book.getOrigId());
|
||||
}
|
||||
|
||||
ADD_ATTR_NOT_EMPTY(entry_node, "date", book.getDate());
|
||||
ADD_ATTR_NOT_EMPTY(entry_node, "url", book.getUrl());
|
||||
|
||||
if (book.getArticleCount())
|
||||
ADD_ATTRIBUTE(entry_node, "articleCount", to_string(book.getArticleCount()));
|
||||
|
||||
if (book.getMediaCount())
|
||||
ADD_ATTRIBUTE(entry_node, "mediaCount", to_string(book.getMediaCount()));
|
||||
|
||||
if (book.getSize())
|
||||
ADD_ATTRIBUTE(entry_node, "size", to_string(book.getSize()>>10));
|
||||
|
||||
ADD_ATTR_NOT_EMPTY(entry_node, "downloadId", book.getDownloadId());
|
||||
}
|
||||
|
||||
#define ADD_TEXT_ENTRY(node, child, value) (node).append_child((child)).append_child(pugi::node_pcdata).set_value((value).c_str())
|
||||
|
||||
void LibXMLDumper::handleBookmark(Bookmark bookmark, pugi::xml_node root_node) {
|
||||
|
||||
auto entry_node = root_node.append_child("bookmark");
|
||||
auto book_node = entry_node.append_child("book");
|
||||
|
||||
try {
|
||||
auto book = library->getBookByIdThreadSafe(bookmark.getBookId());
|
||||
ADD_TEXT_ENTRY(book_node, "id", book.getId());
|
||||
ADD_TEXT_ENTRY(book_node, "title", book.getTitle());
|
||||
ADD_TEXT_ENTRY(book_node, "name", book.getName());
|
||||
ADD_TEXT_ENTRY(book_node, "flavour", book.getFlavour());
|
||||
ADD_TEXT_ENTRY(book_node, "language", book.getCommaSeparatedLanguages());
|
||||
ADD_TEXT_ENTRY(book_node, "date", book.getDate());
|
||||
} catch (...) {
|
||||
ADD_TEXT_ENTRY(book_node, "id", bookmark.getBookId());
|
||||
ADD_TEXT_ENTRY(book_node, "title", bookmark.getBookTitle());
|
||||
ADD_TEXT_ENTRY(book_node, "name", bookmark.getBookName());
|
||||
ADD_TEXT_ENTRY(book_node, "flavour", bookmark.getBookFlavour());
|
||||
ADD_TEXT_ENTRY(book_node, "language", bookmark.getLanguage());
|
||||
ADD_TEXT_ENTRY(book_node, "date", bookmark.getDate());
|
||||
}
|
||||
ADD_TEXT_ENTRY(entry_node, "title", bookmark.getTitle());
|
||||
ADD_TEXT_ENTRY(entry_node, "url", bookmark.getUrl());
|
||||
}
|
||||
|
||||
|
||||
std::string LibXMLDumper::dumpLibXMLContent(const std::vector<std::string>& bookIds)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
|
||||
/* Add the library node */
|
||||
pugi::xml_node libraryNode = doc.append_child("library");
|
||||
|
||||
libraryNode.append_attribute("version") = KIWIX_LIBRARY_VERSION;
|
||||
|
||||
if (library) {
|
||||
for (auto& bookId: bookIds) {
|
||||
handleBook(library->getBookById(bookId), libraryNode);
|
||||
}
|
||||
}
|
||||
return nodeToString(libraryNode);
|
||||
}
|
||||
|
||||
std::string LibXMLDumper::dumpLibXMLBookmark()
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
|
||||
/* Add the library node */
|
||||
pugi::xml_node bookmarksNode = doc.append_child("bookmarks");
|
||||
|
||||
if (library) {
|
||||
for (auto& bookmark: library->getBookmarks(false)) {
|
||||
handleBookmark(bookmark, bookmarksNode);
|
||||
}
|
||||
}
|
||||
return nodeToString(bookmarksNode);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Matthieu Gautier <mgautier@kymeria.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KIWIX_LIBXML_DUMPER_H
|
||||
#define KIWIX_LIBXML_DUMPER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
#include "library.h"
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
/**
|
||||
* A tool to dump a `Library` into a basic library.xml
|
||||
*
|
||||
*/
|
||||
class LibXMLDumper
|
||||
{
|
||||
public:
|
||||
LibXMLDumper() = default;
|
||||
LibXMLDumper(const Library* library);
|
||||
~LibXMLDumper();
|
||||
|
||||
/**
|
||||
* Dump the library.xml
|
||||
*
|
||||
* @param id The id of the library.
|
||||
* @return The library.xml content.
|
||||
*/
|
||||
std::string dumpLibXMLContent(const std::vector<std::string>& bookIds);
|
||||
|
||||
|
||||
/**
|
||||
* Dump the bookmark of the library.
|
||||
*
|
||||
* @return The bookmark.xml content.
|
||||
*/
|
||||
std::string dumpLibXMLBookmark();
|
||||
|
||||
/**
|
||||
* Set the base directory used.
|
||||
*
|
||||
* @param baseDir the base directory to use.
|
||||
*/
|
||||
void setBaseDir(const std::string& baseDir) { this->baseDir = baseDir; }
|
||||
|
||||
/**
|
||||
* Set the library to dump.
|
||||
*
|
||||
* @param library The library to dump.
|
||||
*/
|
||||
void setLibrary(const Library* library) { this->library = library; }
|
||||
|
||||
protected:
|
||||
const kiwix::Library* library;
|
||||
std::string baseDir;
|
||||
private:
|
||||
void handleBook(Book book, pugi::xml_node root_node);
|
||||
void handleBookmark(Bookmark bookmark, pugi::xml_node root_node);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // KIWIX_OPDS_DUMPER_H
|
||||
242
src/manager.cpp
242
src/manager.cpp
@@ -19,90 +19,35 @@
|
||||
|
||||
#include "manager.h"
|
||||
|
||||
#include "tools.h"
|
||||
#include "tools/pathTools.h"
|
||||
|
||||
#include <pugixml.hpp>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <queue>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace kiwix
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// LibraryManipulator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LibraryManipulator::LibraryManipulator(LibraryPtr library)
|
||||
: library(library)
|
||||
{}
|
||||
|
||||
LibraryManipulator::~LibraryManipulator()
|
||||
{}
|
||||
|
||||
bool LibraryManipulator::addBookToLibrary(const Book& book)
|
||||
{
|
||||
const auto ret = library->addBook(book);
|
||||
if ( ret ) {
|
||||
bookWasAddedToLibrary(book);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LibraryManipulator::addBookmarkToLibrary(const Bookmark& bookmark)
|
||||
{
|
||||
library->addBookmark(bookmark);
|
||||
bookmarkWasAddedToLibrary(bookmark);
|
||||
}
|
||||
|
||||
uint32_t LibraryManipulator::removeBooksNotUpdatedSince(Library::Revision rev)
|
||||
{
|
||||
const auto n = library->removeBooksNotUpdatedSince(rev);
|
||||
if ( n != 0 ) {
|
||||
booksWereRemovedFromLibrary();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void LibraryManipulator::bookWasAddedToLibrary(const Book& book)
|
||||
{
|
||||
}
|
||||
|
||||
void LibraryManipulator::bookmarkWasAddedToLibrary(const Bookmark& bookmark)
|
||||
{
|
||||
}
|
||||
|
||||
void LibraryManipulator::booksWereRemovedFromLibrary()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Manager
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* Constructor */
|
||||
Manager::Manager(LibraryManipulator manipulator):
|
||||
Manager::Manager(LibraryManipulator* manipulator):
|
||||
writableLibraryPath(""),
|
||||
manipulator(manipulator)
|
||||
manipulator(manipulator),
|
||||
mustDeleteManipulator(false)
|
||||
{
|
||||
}
|
||||
|
||||
Manager::Manager(LibraryPtr library) :
|
||||
Manager::Manager(Library* library) :
|
||||
writableLibraryPath(""),
|
||||
manipulator(LibraryManipulator(library))
|
||||
manipulator(new DefaultLibraryManipulator(library)),
|
||||
mustDeleteManipulator(true)
|
||||
{
|
||||
}
|
||||
|
||||
/* Destructor */
|
||||
Manager::~Manager()
|
||||
{
|
||||
if (mustDeleteManipulator) {
|
||||
delete manipulator;
|
||||
}
|
||||
}
|
||||
bool Manager::parseXmlDom(const pugi::xml_document& doc,
|
||||
bool readOnly,
|
||||
const std::string& libraryPath,
|
||||
bool trustLibrary)
|
||||
const bool readOnly,
|
||||
const std::string& libraryPath)
|
||||
{
|
||||
pugi::xml_node libraryNode = doc.child("library");
|
||||
|
||||
@@ -114,28 +59,31 @@ bool Manager::parseXmlDom(const pugi::xml_document& doc,
|
||||
|
||||
book.setReadOnly(readOnly);
|
||||
book.updateFromXml(bookNode,
|
||||
removeLastPathElement(libraryPath));
|
||||
removeLastPathElement(libraryPath, true, false));
|
||||
|
||||
if (!trustLibrary && !book.getPath().empty()) {
|
||||
this->readBookFromPath(book.getPath(), &book);
|
||||
/* Update the book properties with the new importer */
|
||||
if (libraryVersion.empty()
|
||||
|| atoi(libraryVersion.c_str()) <= atoi(KIWIX_LIBRARY_VERSION)) {
|
||||
if (!book.getPath().empty()) {
|
||||
this->readBookFromPath(book.getPath(), &book);
|
||||
}
|
||||
}
|
||||
manipulator.addBookToLibrary(book);
|
||||
manipulator->addBookToLibrary(book);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Manager::readXml(const std::string& xml,
|
||||
bool readOnly,
|
||||
const std::string& libraryPath,
|
||||
bool trustLibrary)
|
||||
const bool readOnly,
|
||||
const std::string& libraryPath)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result
|
||||
= doc.load_buffer((void*)xml.data(), xml.size());
|
||||
= doc.load_buffer_inplace((void*)xml.data(), xml.size());
|
||||
|
||||
if (result) {
|
||||
this->parseXmlDom(doc, readOnly, libraryPath, trustLibrary);
|
||||
this->parseXmlDom(doc, readOnly, libraryPath);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -164,7 +112,7 @@ bool Manager::parseOpdsDom(const pugi::xml_document& doc, const std::string& url
|
||||
book.updateFromOpds(entryNode, urlHost);
|
||||
|
||||
/* Update the book properties with the new importer */
|
||||
manipulator.addBookToLibrary(book);
|
||||
manipulator->addBookToLibrary(book);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -176,7 +124,7 @@ bool Manager::readOpds(const std::string& content, const std::string& urlHost)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result
|
||||
= doc.load_buffer((void*)content.data(), content.size());
|
||||
= doc.load_buffer_inplace((void*)content.data(), content.size());
|
||||
|
||||
if (result) {
|
||||
this->parseOpdsDom(doc, urlHost);
|
||||
@@ -186,22 +134,21 @@ bool Manager::readOpds(const std::string& content, const std::string& urlHost)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Manager::readFile(
|
||||
const std::string& path,
|
||||
bool readOnly,
|
||||
bool trustLibrary)
|
||||
bool Manager::readFile(const std::string& path, const bool readOnly)
|
||||
{
|
||||
return this->readFile(path, path, readOnly);
|
||||
}
|
||||
|
||||
bool Manager::readFile(const std::string& nativePath,
|
||||
const std::string& UTF8Path,
|
||||
const bool readOnly)
|
||||
{
|
||||
bool retVal = true;
|
||||
pugi::xml_document doc;
|
||||
|
||||
#ifdef _WIN32
|
||||
pugi::xml_parse_result result = doc.load_file(Utf8ToWide(path).c_str());
|
||||
#else
|
||||
pugi::xml_parse_result result = doc.load_file(path.c_str());
|
||||
#endif
|
||||
pugi::xml_parse_result result = doc.load_file(nativePath.c_str());
|
||||
|
||||
if (result) {
|
||||
this->parseXmlDom(doc, readOnly, path, trustLibrary);
|
||||
this->parseXmlDom(doc, readOnly, UTF8Path);
|
||||
} else {
|
||||
retVal = false;
|
||||
}
|
||||
@@ -210,7 +157,7 @@ bool Manager::readFile(
|
||||
* able to know where to save the library if new content are
|
||||
* available */
|
||||
if (!readOnly) {
|
||||
this->writableLibraryPath = path;
|
||||
this->writableLibraryPath = UTF8Path;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
@@ -227,19 +174,19 @@ std::string Manager::addBookFromPathAndGetId(const std::string& pathToOpen,
|
||||
kiwix::Book book;
|
||||
|
||||
if (this->readBookFromPath(pathToOpen, &book)) {
|
||||
if (!pathToSave.empty() && pathToSave != pathToOpen) {
|
||||
if (pathToSave != pathToOpen) {
|
||||
book.setPath(isRelativePath(pathToSave)
|
||||
? computeAbsolutePath(
|
||||
removeLastPathElement(writableLibraryPath),
|
||||
removeLastPathElement(writableLibraryPath, true, false),
|
||||
pathToSave)
|
||||
: pathToSave);
|
||||
}
|
||||
|
||||
if (!checkMetaData
|
||||
|| (!book.getTitle().empty() && !book.getLanguages().empty()
|
||||
|| (checkMetaData && !book.getTitle().empty() && !book.getLanguage().empty()
|
||||
&& !book.getDate().empty())) {
|
||||
book.setUrl(url);
|
||||
manipulator.addBookToLibrary(book);
|
||||
manipulator->addBookToLibrary(book);
|
||||
return book.getId();
|
||||
}
|
||||
}
|
||||
@@ -259,69 +206,14 @@ bool Manager::addBookFromPath(const std::string& pathToOpen,
|
||||
.empty());
|
||||
}
|
||||
|
||||
void Manager::addBooksFromDirectory(const std::string& path,
|
||||
const bool verboseFlag)
|
||||
{
|
||||
std::set<std::string> iteratedDirs;
|
||||
std::queue<std::string> dirQueue;
|
||||
dirQueue.push(fs::absolute(path).u8string());
|
||||
int totalBooksAdded = 0;
|
||||
if (verboseFlag)
|
||||
std::cout << "Adding books from the directory tree: " << dirQueue.front() << std::endl;
|
||||
|
||||
while (!dirQueue.empty()) {
|
||||
const auto currentPath = dirQueue.front();
|
||||
dirQueue.pop();
|
||||
if (verboseFlag)
|
||||
std::cout << "Visiting directory: " << currentPath << std::endl;
|
||||
for (const auto& dirEntry : fs::directory_iterator(currentPath)) {
|
||||
auto resolvedPath = dirEntry.path();
|
||||
if (fs::is_symlink(dirEntry)) {
|
||||
try {
|
||||
resolvedPath = fs::canonical(dirEntry.path());
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Could not resolve symlink " << resolvedPath.u8string() << " to a valid path. Skipping..." << std::endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const std::string pathString = resolvedPath.u8string();
|
||||
std::string resolvedPathExtension = resolvedPath.extension();
|
||||
std::transform(resolvedPathExtension.begin(), resolvedPathExtension.end(), resolvedPathExtension.begin(),
|
||||
[](unsigned char c){ return std::tolower(c); });
|
||||
if (fs::is_directory(resolvedPath)) {
|
||||
if (iteratedDirs.find(pathString) == iteratedDirs.end())
|
||||
dirQueue.push(pathString);
|
||||
else if (verboseFlag)
|
||||
std::cout << "Already iterated over " << pathString << ". Skipping..." << std::endl;
|
||||
} else if (resolvedPathExtension == ".zim" || resolvedPathExtension == ".zimaa") {
|
||||
if (!this->addBookFromPath(pathString, pathString, "", false)) {
|
||||
std::cerr << "Could not add " << pathString << " into the library." << std::endl;
|
||||
} else if (verboseFlag) {
|
||||
std::cout << "Added " << pathString << " into the library." << std::endl;
|
||||
totalBooksAdded++;
|
||||
}
|
||||
} else if (verboseFlag) {
|
||||
std::cout << "Skipped " << pathString << " - unsupported file type or permission denied." << std::endl;
|
||||
}
|
||||
}
|
||||
iteratedDirs.insert(currentPath);
|
||||
}
|
||||
|
||||
if (verboseFlag)
|
||||
std::cout << "Traversal completed. Total books added: " << totalBooksAdded << std::endl;
|
||||
}
|
||||
|
||||
bool Manager::readBookFromPath(const std::string& path, kiwix::Book* book)
|
||||
{
|
||||
std::string tmp_path = path;
|
||||
if (isRelativePath(path)) {
|
||||
tmp_path = computeAbsolutePath(getCurrentDirectory(), path);
|
||||
}
|
||||
try {
|
||||
zim::Archive archive(tmp_path);
|
||||
book->update(archive);
|
||||
kiwix::Reader reader(path);
|
||||
book->update(reader);
|
||||
book->setPathValid(true);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Invalid " << path << " : " << e.what() << std::endl;
|
||||
book->setPathValid(false);
|
||||
return false;
|
||||
}
|
||||
@@ -329,44 +221,4 @@ bool Manager::readBookFromPath(const std::string& path, kiwix::Book* book)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Manager::readBookmarkFile(const std::string& path)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result = doc.load_file(path.c_str());
|
||||
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pugi::xml_node libraryNode = doc.child("bookmarks");
|
||||
|
||||
for (pugi::xml_node node = libraryNode.child("bookmark"); node;
|
||||
node = node.next_sibling("bookmark")) {
|
||||
kiwix::Bookmark bookmark;
|
||||
|
||||
bookmark.updateFromXml(node);
|
||||
|
||||
manipulator.addBookmarkToLibrary(bookmark);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Manager::reload(const Paths& paths)
|
||||
{
|
||||
const auto libRevision = manipulator.getLibrary()->getRevision();
|
||||
for (std::string path : paths) {
|
||||
if (!path.empty()) {
|
||||
if ( kiwix::isRelativePath(path) )
|
||||
path = kiwix::computeAbsolutePath(kiwix::getCurrentDirectory(), path);
|
||||
|
||||
if (!readFile(path, false, true)) {
|
||||
throw std::runtime_error("Failed to load the XML library file '" + path + "'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
manipulator.removeBooksNotUpdatedSince(libRevision);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user