diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 49bde477a..cc86d447d 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -122,8 +122,6 @@ jobs: -DCMAKE_CXX_FLAGS="-Werror" -DCMAKE_INSTALL_PREFIX=install -DODR_TEST=ON - -DODR_WITH_PDF2HTMLEX=ON - -DODR_WITH_WVWARE=ON -DODR_WITH_LIBMAGIC=ON -DODR_BUNDLE_ASSETS=ON ${{ matrix.bindings && '-DODR_JNI=ON -DODR_PYTHON=ON' || '' }} @@ -137,8 +135,6 @@ jobs: -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=install -DODR_TEST=ON - -DODR_WITH_PDF2HTMLEX=OFF - -DODR_WITH_WVWARE=OFF -DODR_WITH_LIBMAGIC=OFF - name: build @@ -240,7 +236,9 @@ jobs: fail-fast: false matrix: include: - # fails at the moment because of pdf2htmlex + # Disabled while pdf2htmlEX was still built; that blocker is gone, but + # the reference output is generated on macOS, so re-enabling needs a + # cross-platform comparison run first. #- { os: ubuntu-24.04, host_profile: ubuntu-24.04-clang-18 } #- { os: ubuntu-24.04, host_profile: ubuntu-24.04-gcc-14 } - { os: macos-26, host_profile: macos-26-armv8-clang-14 } diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 021413e4a..11642be75 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -40,8 +40,9 @@ jobs: # everything that needs the wheel's own, reduced dependency set. wheels: runs-on: ${{ matrix.os }} - # Builds the reduced dependency set that `pyproject.toml` pins (no - # pdf2htmlEX/wvWare), so it cannot share a cache with `build_test`. + # Builds the wheel-specific configuration that `pyproject.toml` pins + # (static, no cli/tests, bundled assets), so it cannot share a cache with + # `build_test`. env: CACHE_FLAVOR: wheel strategy: @@ -104,16 +105,13 @@ jobs: restore-keys: | ccache-${{ env.CACHE_FLAVOR }}-${{ matrix.host_profile }}-${{ env.CCACHE_KEY_SUFFIX }}- - # Match the dependency set that pyproject.toml enables. pdf2htmlEX and - # wvWare stay off (their runtime data cannot ship inside the wheel); - # libmagic stays on and `bundle_assets` bridges its database path into the - # build so `magic.mgc` lands in `pyodr/data`. + # Match the dependency set that pyproject.toml enables. libmagic stays on + # and `bundle_assets` bridges its database path into the build so + # `magic.mgc` lands in `pyodr/data`. - name: conan install run: > conan install . -o '&:with_python=True' - -o '&:with_pdf2htmlEX=False' - -o '&:with_wvWare=False' -o '&:bundle_assets=True' --profile:host '${{ matrix.host_profile }}' --profile:build '${{ matrix.build_profile }}' diff --git a/AGENTS.md b/AGENTS.md index aa5f014ef..fc2b43d95 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -59,8 +59,7 @@ bytes ─▶ magic/open_strategy ─▶ DecodedFile ─▶ Document ─▶ Eleme | `src/odr/internal/odf/` | OpenDocument (odt/ods/odp/odg); see [`odf/AGENTS.md`](src/odr/internal/odf/AGENTS.md). | | `src/odr/internal/ooxml/` | OOXML (docx/pptx/xlsx); see [`ooxml/AGENTS.md`](src/odr/internal/ooxml/AGENTS.md) + per-format docs. | | `src/odr/internal/oldms/` | **Legacy MS binary** (.doc/.ppt/.xls). | -| `src/odr/internal/oldms_wvware/` | Alternative .doc decoder via wvWare. | -| `src/odr/internal/pdf/`, `pdf_poppler/` | PDF (own parser + poppler/pdf2htmlEX path). | +| `src/odr/internal/pdf/` | PDF (own parser). | | `src/odr/internal/{csv,json,text,svm}/` | Smaller formats. | | `cli/src/` | CLI tools: `translate`, `back_translate`, `meta`, `server`. | | `python/` | Python bindings (`pyodr`, pybind11); see [`python/AGENTS.md`](python/AGENTS.md). | @@ -86,9 +85,9 @@ cmake --build cmake-build-relwithdebinfo --target translate # CLI: file → HTM when really necessary. - **Run the test binary from the build dir** so output stays out of the repo tree. - **For debugging, prefer the `translate` CLI** on a single file over the suite. -- CMake options (`CMakeLists.txt`): `ODR_TEST`, `ODR_CLI`, `ODR_WITH_PDF2HTMLEX`, - `ODR_WITH_WVWARE`, `ODR_WITH_LIBMAGIC`, `ODR_PYTHON`, `ODR_CLANG_TIDY`. A new - `.cpp` must be added to `ODR_SOURCE_FILES`. +- CMake options (`CMakeLists.txt`): `ODR_TEST`, `ODR_CLI`, `ODR_WITH_LIBMAGIC`, + `ODR_PYTHON`, `ODR_CLANG_TIDY`. A new `.cpp` must be added to + `ODR_SOURCE_FILES`. - **Test data lives in git submodules** under `test/data/`. ## Conventions diff --git a/CMakeLists.txt b/CMakeLists.txt index 310a42244..ffd1ffcd7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,12 +15,7 @@ option(ODR_TEST "enable tests" OFF) option(ODR_CLI "enable command line interface" ON) option(ODR_WITH_HTTP_SERVER "Build the HTTP server (requires cpp-httplib)" ON) option(ODR_CLANG_TIDY "Run clang-tidy static analysis" OFF) -option(WITH_PDF2HTMLEX "Deprecated: `ODR_WITH_PDF2HTMLEX` instead! Build with pdf2htmlEX" ON) -option(WITH_WVWARE "Deprecated: `ODR_WITH_WVWARE` instead! Build with wvWare" ON) -option(WITH_LIBMAGIC "Deprecated: `ODR_WITH_WVWARE` instead! Build with libmagic" ON) -option(ODR_WITH_PDF2HTMLEX "Build with pdf2htmlEX" "${WITH_PDF2HTMLEX}") -option(ODR_WITH_WVWARE "Build with wvWare" "${WITH_WVWARE}") -option(ODR_WITH_LIBMAGIC "Build with libmagic" "${WITH_LIBMAGIC}") +option(ODR_WITH_LIBMAGIC "Build with libmagic" ON) option(ODR_BUNDLE_ASSETS "Bundle assets during build and install" OFF) option(ODR_PYTHON "Build Python bindings" OFF) option(ODR_JNI "Build JNI bindings" OFF) @@ -135,7 +130,6 @@ set(ODR_SOURCE_FILES "src/odr/internal/html/html_writer.cpp" "src/odr/internal/html/image_file.cpp" "src/odr/internal/html/pdf_file.cpp" - "src/odr/internal/html/pdf2htmlex_wrapper.hpp" "src/odr/internal/html/text_file.cpp" "src/odr/internal/json/json_file.cpp" @@ -270,7 +264,7 @@ set(ODR_INSTALL_ODR_DATA_PATH "${CMAKE_INSTALL_DATADIR}") # Validate an injected data-file path before it is used to bundle assets. # -# These paths (FONTCONFIG_DATA_PATH, POPPLER_DATA_PATH, ...) are consumed but +# These paths (LIBMAGIC_DATABASE_PATH, ...) are consumed but # never discovered by CMake — they must be injected from outside via `-D...=`; # our conanfile.py bridges them from the dependency runenv. A consumer that # builds odrcore without that bridge left the variable empty, and @@ -307,66 +301,6 @@ if (ODR_WITH_HTTP_SERVER) ODR_WITH_HTTP_SERVER ) endif () -if (ODR_WITH_PDF2HTMLEX) - find_package(pdf2htmlEX REQUIRED) - find_package(poppler REQUIRED) - target_sources(odr - PRIVATE - "src/odr/internal/html/pdf2htmlex_wrapper.cpp" - "src/odr/internal/pdf_poppler/poppler_pdf_file.cpp" - ) - target_link_libraries(odr - PRIVATE - pdf2htmlex::pdf2htmlex - poppler::poppler - ) - target_compile_definitions(odr - PRIVATE - ODR_WITH_PDF2HTMLEX - ) - - if (ODR_BUNDLE_ASSETS) - odr_require_data_path("${FONTCONFIG_DATA_PATH}" FONTCONFIG_DATA_PATH) - odr_require_data_path("${POPPLER_DATA_PATH}" POPPLER_DATA_PATH) - odr_require_data_path("${PDF2HTMLEX_DATA_PATH}" PDF2HTMLEX_DATA_PATH) - - set(ODR_BUILD_FONTCONFIG_DATA_PATH "${ODR_BUILD_ODR_DATA_PATH}/fontconfig") - set(ODR_BUILD_POPPLER_DATA_PATH "${ODR_BUILD_ODR_DATA_PATH}/poppler") - set(ODR_BUILD_PDF2HTMLEX_DATA_PATH "${ODR_BUILD_ODR_DATA_PATH}/pdf2htmlex") - - file(COPY "${FONTCONFIG_DATA_PATH}/" DESTINATION "${ODR_BUILD_FONTCONFIG_DATA_PATH}") - file(COPY "${POPPLER_DATA_PATH}/" DESTINATION "${ODR_BUILD_POPPLER_DATA_PATH}") - file(COPY "${PDF2HTMLEX_DATA_PATH}/" DESTINATION "${ODR_BUILD_PDF2HTMLEX_DATA_PATH}") - - set(ODR_INSTALL_FONTCONFIG_DATA_PATH "${ODR_INSTALL_ODR_DATA_PATH}/fontconfig") - set(ODR_INSTALL_POPPLER_DATA_PATH "${ODR_INSTALL_ODR_DATA_PATH}/poppler") - set(ODR_INSTALL_PDF2HTMLEX_DATA_PATH "${ODR_INSTALL_ODR_DATA_PATH}/pdf2htmlex") - else () - set(ODR_BUILD_FONTCONFIG_DATA_PATH "${FONTCONFIG_DATA_PATH}") - set(ODR_BUILD_POPPLER_DATA_PATH "${POPPLER_DATA_PATH}") - set(ODR_BUILD_PDF2HTMLEX_DATA_PATH "${PDF2HTMLEX_DATA_PATH}") - - set(ODR_INSTALL_FONTCONFIG_DATA_PATH "${FONTCONFIG_DATA_PATH}") - set(ODR_INSTALL_POPPLER_DATA_PATH "${POPPLER_DATA_PATH}") - set(ODR_INSTALL_PDF2HTMLEX_DATA_PATH "${PDF2HTMLEX_DATA_PATH}") - endif () -endif () -if (ODR_WITH_WVWARE) - find_package(wvware REQUIRED) - target_sources(odr - PRIVATE - "src/odr/internal/html/wvware_wrapper.cpp" - "src/odr/internal/oldms_wvware/wvware_oldms_file.cpp" - ) - target_link_libraries(odr - PRIVATE - wvware::wvware - ) - target_compile_definitions(odr - PRIVATE - ODR_WITH_WVWARE - ) -endif () if (ODR_WITH_LIBMAGIC) find_package(libmagic REQUIRED) target_sources(odr diff --git a/README.md b/README.md index a9379d85d..e11e08392 100644 --- a/README.md +++ b/README.md @@ -64,12 +64,6 @@ Scripts and Docker images can be found here https://github.com/opendocument-app/ OpenDocument.core is licensed under the [Mozilla Public License 2.0](LICENSE) (`MPL-2.0`). -Optional build features link the library against third-party components under -their own terms — notably `pdf2htmlEX` (`ODR_WITH_PDF2HTMLEX`) and `wvWare` -(`ODR_WITH_WVWARE`), both GPL-licensed. Enabling them and distributing the -combined binary may subject the whole to those components' license terms; consult -each project's own license before redistributing. - -Separately, the committed PDF font/encoding tables in `src/odr/internal/pdf/` are +The committed PDF font/encoding tables in `src/odr/internal/pdf/` are generated from third-party source data whose provenance and terms are documented in [`tools/pdf/THIRD_PARTY_LICENSES.md`](tools/pdf/THIRD_PARTY_LICENSES.md). diff --git a/cli/src/server.cpp b/cli/src/server.cpp index b591d7a3e..2f6798333 100644 --- a/cli/src/server.cpp +++ b/cli/src/server.cpp @@ -23,8 +23,6 @@ int main(const int argc, char **argv) { } DecodePreference decode_preference; - decode_preference.engine_priority = { - DecoderEngine::poppler, DecoderEngine::wvware, DecoderEngine::odr}; decode_preference.as_file_type = FileType::zip; DecodedFile decoded_file{input, decode_preference, *logger}; diff --git a/conan.lock b/conan.lock index d4fd9138c..36313d6e1 100644 --- a/conan.lock +++ b/conan.lock @@ -4,73 +4,28 @@ "zstd/1.5.7#b68ca8e3de04ba5957761751d1d661f4%1760955092.069", "zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1777558780.503", "xz_utils/5.8.3#a8432fead347c69d8b2737c35f936132%1775752656.4", - "wvware/1.2.9-odr#ecdcc87eeee4ba3171fc52b885ffcd37%1784987064.234467", "vincentlaucsb-csv-parser/2.3.0#ac67e368e82c9e3da4a663c35e3a1b2f%1718528275.177", - "util-linux-libuuid/2.41.2#ee8e33ba15c17c0140643e0bd93c0b6f%1765881086.29", "utfcpp/4.0.9#b5eb56fe6b829b6f3eb8da167c4f41b2%1773905531.586", "uchardet/0.0.8#6ab25e452021fcdb560f4e37f4a27bc1%1759735438.978", "pybind11/2.13.6#42746850cd4c68d1b1ea42de456c2182%1755673714.548", "pugixml/1.15#979e88f4fafbfe3585d2c0510a071cc7%1739435725.483", - "poppler-data/0.4.12-odr#06cdb12e4cab52261a5eb6c7d7dad273%1784987064.081555", - "poppler/26.05.0-odr#1bea719ddff7adcea402ab5cc230cddb%1784987063.93038", - "pixman/0.46.2#88b157b4faa6474a6028c2ba2a987924%1752742515.414", - "pdf2htmlex/0.18.8.rc1-odr-git-732fd68#3740316d902d99246da134b0d5f97276%1784987063.4659111", - "pcre2/10.42#9a35f5089feb875ec61a38eca364ce77%1743524593.693", - "openjpeg/2.5.4#372fbc2b4348d45ab0c0a62a8475dc2f%1760446899.685", "nlohmann_json/3.12.0#2d634ab0ec8d9f56353e5ccef6d6612c%1744735883.94", "miniz/3.0.2#bfbce07c6654293cce27ee24129d2df7%1743673472.805", - "lzo/2.10#f00b10acc508cea70645727d970a23e1%1759909644.842", - "libxml2/2.12.7#1c4d20b7ab8b618ce699733723ba4df6%1721306327.767", - "libselinux/3.6#5a78ff6ae5034eeaac8da723361a8ce4%1717655459.344", - "libpng/1.6.58#19cb72905ae54f54948401f753faa2c1%1776606503.628", "libmagic/5.45#791d5bad38d33272bb120994a198b1ac%1727273086.09", - "libjpeg/9f#8b1b89da851ad9172565c35f14e23c4c%1780476337.068", - "libiconv/1.17#9923bc6dc6f106646d6967e0039a5ada%1774021608.288", - "libgsf/1.14.52#5dbc15a9ac6f146fa648766f8691256e%1784987058.932805", - "libgettext/0.22#b09eea019e19b9b9c46d8f1da7d75444%1765809130.834", - "libffi/3.4.8#a045c00fb26779635e3bed40e80c5254%1753360042.396", - "libelf/0.8.13#ba59bbc89757ed62cfd7690a73bf81be%1741781951.327", - "lcms/2.17#3feb06eea368c52c82f50107cd7694cd%1753693316.094", "gtest/1.14.0#f8f0757a574a8dd747d16af62d6eb1b7%1743410807.169", - "glib/2.81.0-odr#0436d4fbe7682722ede5964a63953c1d%1784987058.779003", - "giflib/5.2.2#b445ec67bae61a96ddf0fa5614afde18%1773315754.794", - "freetype/2.14.1#40f1e4af5db7d8155f9ecabd09973280%1762374429.281", - "fontforge/20251009#846770e19fc4ee3234e0a39344a71211%1784987058.624506", - "fontconfig/2.15.0-odr#5681bcb942193569ee95215b93ed9fb0%1784987058.316003", - "expat/2.8.1#e2fa0a1a12da326521a3d622a475047a%1780484982.662", "cryptopp/8.9.0#7a51e0038756b21bc3a6b82d681d5906%1758206597.119", "cpp-httplib/0.16.3#7aa89fbb81ffd19539a49fc132502966%1748426320.106", - "cairo/1.18.0-odr#e2979af10b4da6ece999e32d272ffabc%1784987058.1596658", "bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1762886692.465", - "brotli/1.1.0#3f631ef77008f7b5eb388780116371a3%1764862343.045", - "boost/1.90.0#ddd0d973741acbebe7c3b8dfbfd005eb%1778050994.937", "argon2/20190702-odr#965901884bc82ec8a7c0a1305d42c127%1784987057.981858" ], "build_requires": [ "zstd/1.5.7#b68ca8e3de04ba5957761751d1d661f4%1760955092.069", "zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1777558780.503", "xz_utils/5.8.3#a8432fead347c69d8b2737c35f936132%1775752656.4", - "pkgconf/2.5.1#93c2051284cba1279494a43a4fcfeae2%1757684701.089", - "pkgconf/2.2.0#4ac315b50ef734072b00ff3aacbf52bf%1755505628.021", - "pkgconf/2.1.0#21f96520faf7660b99f872e956d2ac13%1755505630.82", - "pcre2/10.42#9a35f5089feb875ec61a38eca364ce77%1743524593.693", - "ninja/1.13.2#c8c5dc2a52ed6e4e42a66d75b4717ceb%1764096931.974", - "meson/1.10.2#9d2d10681fe7fe61c788c58626c89b25%1775558003.754", - "meson/1.9.1#abbc783cd297bedce14581b4aec060b8%1758626166.349", "m4/1.4.19#34c4bbc3eeebe98ca6edf2f52d602e7d%1777282960.259", "libtool/2.4.7#14e7739cc128bc1623d2ed318008e47e%1755679003.847", - "libselinux/3.6#5a78ff6ae5034eeaac8da723361a8ce4%1717655459.344", "libmagic/5.45#791d5bad38d33272bb120994a198b1ac%1727273086.09", - "libiconv/1.17#9923bc6dc6f106646d6967e0039a5ada%1774021608.288", - "libgettext/0.22#b09eea019e19b9b9c46d8f1da7d75444%1765809130.834", - "libffi/3.4.8#a045c00fb26779635e3bed40e80c5254%1753360042.396", - "libelf/0.8.13#ba59bbc89757ed62cfd7690a73bf81be%1741781951.327", - "gtk-doc-stub/cci.20181216#09072d684ce1458596b44a30a747494c%1687277608.37", - "gperf/3.1#a7afdf8f7cccdc2dcd4d962370c33d4f%1755780571.156", "gnu-config/cci.20210814#466e9d4d7779e1c142443f7ea44b4284%1762363589.329", - "glib/2.81.0-odr#0436d4fbe7682722ede5964a63953c1d%1784987058.779003", - "gettext/0.26#28c867efd4914f03c6c05da08a23c35b%1765299118.633", - "flex/2.6.4#efa781fc5088b47c895bd4eef6911f2e%1761560242.855", "cmake/4.3.2#5bae0b181463ca4dc3e924a981367ee6%1779785720.872", "cmake/3.31.12#173a926abc2b77f03c826b6fd6539426%1779785723.158", "bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1762886692.465", diff --git a/conanfile.py b/conanfile.py index f5a750ae8..3e64ccaac 100644 --- a/conanfile.py +++ b/conanfile.py @@ -17,8 +17,6 @@ class OpenDocumentCoreConan(ConanFile): options = { "shared": [True, False], "fPIC": [True, False], - "with_pdf2htmlEX": [True, False], - "with_wvWare": [True, False], "with_libmagic": [True, False], "with_http_server": [True, False], "with_cli": [True, False], @@ -29,8 +27,6 @@ class OpenDocumentCoreConan(ConanFile): default_options = { "shared": False, "fPIC": True, - "with_pdf2htmlEX": True, - "with_wvWare": True, "with_libmagic": True, "with_http_server": True, "with_cli": True, @@ -44,8 +40,6 @@ class OpenDocumentCoreConan(ConanFile): def config_options(self): if self.settings.os == "Windows": del self.options.fPIC - del self.options.with_pdf2htmlEX - del self.options.with_wvWare del self.options.with_libmagic def requirements(self): @@ -56,10 +50,6 @@ def requirements(self): self.requires("vincentlaucsb-csv-parser/2.3.0") self.requires("uchardet/0.0.8") self.requires("utfcpp/4.0.9") - if self.options.get_safe("with_pdf2htmlEX", False): - self.requires("pdf2htmlex/0.18.8.rc1-odr-git-732fd68") - if self.options.get_safe("with_wvWare", False): - self.requires("wvware/1.2.9-odr") if self.options.get_safe("with_http_server", False): self.requires("cpp-httplib/0.16.3") self.requires("argon2/20190702-odr") @@ -83,8 +73,6 @@ def generate(self): tc = CMakeToolchain(self) tc.variables["CMAKE_PROJECT_VERSION"] = self.version tc.variables["ODR_TEST"] = False - tc.variables["ODR_WITH_PDF2HTMLEX"] = self.options.get_safe("with_pdf2htmlEX", False) - tc.variables["ODR_WITH_WVWARE"] = self.options.get_safe("with_wvWare", False) tc.variables["ODR_WITH_LIBMAGIC"] = self.options.get_safe("with_libmagic", False) tc.variables["ODR_WITH_HTTP_SERVER"] = self.options.get_safe("with_http_server", False) tc.variables["ODR_CLI"] = self.options.get_safe("with_cli", True) @@ -93,14 +81,11 @@ def generate(self): tc.variables["ODR_BUNDLE_ASSETS"] = self.options.get_safe("bundle_assets", False) # Get runenv info, exported by package_info() of dependencies - # We need to obtain PDF2HTMLEX_DATA_DIR, POPPLER_DATA_DIR, FONTCONFIG_PATH and WVDATADIR + # We need to obtain MAGIC runenv_info = Environment() for dep in self.dependencies.host.topological_sort.values(): runenv_info.compose_env(dep.runenv_info) envvars = runenv_info.vars(self) - tc.variables["FONTCONFIG_DATA_PATH"] = envvars.get("FONTCONFIG_PATH") - tc.variables["POPPLER_DATA_PATH"] = envvars.get("POPPLER_DATA_DIR") - tc.variables["PDF2HTMLEX_DATA_PATH"] = envvars.get("PDF2HTMLEX_DATA_DIR") tc.variables["LIBMAGIC_DATABASE_PATH"] = envvars.get("MAGIC") tc.generate() diff --git a/docs/design/README.md b/docs/design/README.md index 85696b76a..1913a1dfc 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -40,8 +40,6 @@ Eases lifetime management; consistent with value semantics for the user-facing API. - Collapse `FileMeta` into a single type. The nested `DocumentMeta` does not earn the extra indirection. -- drop `wvWare` (the alternative `.doc` decoder, `oldms_wvware/`) -- drop `pdf2htmlEX` (the poppler/pdf2htmlEX PDF path) ### Document index diff --git a/jni/README.md b/jni/README.md index 0a93fc773..b83b17d6f 100644 --- a/jni/README.md +++ b/jni/README.md @@ -73,8 +73,7 @@ standalone against an installed `odrcore` package. Rendering uses shipped assets (CSS/JS). Point the library at them via `GlobalParams.setOdrCoreDataPath(...)` or the `ODR_CORE_DATA_PATH` environment variable (the tests read it; for in-tree builds it is `build/data`). The -optional pdf2htmlEX/wvWare/libmagic backends have their own paths on -`GlobalParams`. +optional libmagic backend has its own path on `GlobalParams`. ## Notes diff --git a/jni/java/app/opendocument/core/DecoderEngine.java b/jni/java/app/opendocument/core/DecoderEngine.java index 1b355ed79..c5755d843 100644 --- a/jni/java/app/opendocument/core/DecoderEngine.java +++ b/jni/java/app/opendocument/core/DecoderEngine.java @@ -2,7 +2,7 @@ /** Mirrors {@code odr::DecoderEngine}; constant order must match the C++ declaration. */ public enum DecoderEngine { - ODR, POPPLER, WVWARE; + ODR; static DecoderEngine fromNative(int code) { return code < 0 ? null : values()[code]; diff --git a/jni/java/app/opendocument/core/GlobalParams.java b/jni/java/app/opendocument/core/GlobalParams.java index f449582a1..614cb5d19 100644 --- a/jni/java/app/opendocument/core/GlobalParams.java +++ b/jni/java/app/opendocument/core/GlobalParams.java @@ -8,22 +8,10 @@ public final class GlobalParams { public static native String odrCoreDataPath(); - public static native String fontconfigDataPath(); - - public static native String popplerDataPath(); - - public static native String pdf2htmlexDataPath(); - public static native String libmagicDatabasePath(); public static native void setOdrCoreDataPath(String path); - public static native void setFontconfigDataPath(String path); - - public static native void setPopplerDataPath(String path); - - public static native void setPdf2htmlexDataPath(String path); - public static native void setLibmagicDatabasePath(String path); private GlobalParams() {} diff --git a/jni/src/jni_core.cpp b/jni/src/jni_core.cpp index 51ba91d22..1f16ba571 100644 --- a/jni/src/jni_core.cpp +++ b/jni/src/jni_core.cpp @@ -230,29 +230,6 @@ Java_app_opendocument_core_GlobalParams_odrCoreDataPath(JNIEnv *env, jclass) { }); } -extern "C" JNIEXPORT jstring JNICALL -Java_app_opendocument_core_GlobalParams_fontconfigDataPath(JNIEnv *env, - jclass) { - return guarded(env, [&] { - return to_jstring(env, odr::GlobalParams::fontconfig_data_path()); - }); -} - -extern "C" JNIEXPORT jstring JNICALL -Java_app_opendocument_core_GlobalParams_popplerDataPath(JNIEnv *env, jclass) { - return guarded(env, [&] { - return to_jstring(env, odr::GlobalParams::poppler_data_path()); - }); -} - -extern "C" JNIEXPORT jstring JNICALL -Java_app_opendocument_core_GlobalParams_pdf2htmlexDataPath(JNIEnv *env, - jclass) { - return guarded(env, [&] { - return to_jstring(env, odr::GlobalParams::pdf2htmlex_data_path()); - }); -} - extern "C" JNIEXPORT jstring JNICALL Java_app_opendocument_core_GlobalParams_libmagicDatabasePath(JNIEnv *env, jclass) { @@ -269,32 +246,6 @@ Java_app_opendocument_core_GlobalParams_setOdrCoreDataPath(JNIEnv *env, jclass, }); } -extern "C" JNIEXPORT void JNICALL -Java_app_opendocument_core_GlobalParams_setFontconfigDataPath(JNIEnv *env, - jclass, - jstring path) { - guarded(env, [&] { - odr::GlobalParams::set_fontconfig_data_path(to_string(env, path)); - }); -} - -extern "C" JNIEXPORT void JNICALL -Java_app_opendocument_core_GlobalParams_setPopplerDataPath(JNIEnv *env, jclass, - jstring path) { - guarded(env, [&] { - odr::GlobalParams::set_poppler_data_path(to_string(env, path)); - }); -} - -extern "C" JNIEXPORT void JNICALL -Java_app_opendocument_core_GlobalParams_setPdf2htmlexDataPath(JNIEnv *env, - jclass, - jstring path) { - guarded(env, [&] { - odr::GlobalParams::set_pdf2htmlex_data_path(to_string(env, path)); - }); -} - extern "C" JNIEXPORT void JNICALL Java_app_opendocument_core_GlobalParams_setLibmagicDatabasePath(JNIEnv *env, jclass, diff --git a/pyproject.toml b/pyproject.toml index 45398d167..939660729 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,10 +61,6 @@ ODR_PYTHON = "ON" ODR_CLI = "OFF" ODR_TEST = "OFF" BUILD_SHARED_LIBS = "OFF" -# Keep wheels self-contained: skip the components whose runtime data cannot be -# bundled into the package (PDF rendering falls back to the built-in parser). -ODR_WITH_PDF2HTMLEX = "OFF" -ODR_WITH_WVWARE = "OFF" # libmagic's database is just a data file, so it can ship: `ODR_BUNDLE_ASSETS` # copies `magic.mgc` next to the odr.js assets, `python/CMakeLists.txt` installs # that directory as `pyodr/data`, and `pyodr/__init__.py` points `GlobalParams` diff --git a/python/README.md b/python/README.md index 36f6cd410..e588a8cb6 100644 --- a/python/README.md +++ b/python/README.md @@ -33,13 +33,10 @@ PYTHONPATH=build/python ODR_CORE_DATA_PATH=build/data python -m pytest python/te `pip install .` from the repository root builds a wheel via scikit-build-core (see the root `pyproject.toml`); run `conan install` first and point `CMAKE_ARGS` at the generated `conan_toolchain.cmake` so the C++ dependencies -resolve. Wheels build without pdf2htmlEX/wvWare (their runtime data cannot ship -inside the wheel) but with libmagic, whose database is bundled — so match those -options: +resolve. Wheels bundle libmagic's database, so match that option: ```bash -conan install . -o '&:with_python=True' -o '&:with_pdf2htmlEX=False' \ - -o '&:with_wvWare=False' -o '&:bundle_assets=True' --build missing +conan install . -o '&:with_python=True' -o '&:bundle_assets=True' --build missing CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=$PWD/conan_toolchain.cmake" pip install . ``` diff --git a/python/src/bind_core.cpp b/python/src/bind_core.cpp index b9a94cef5..7c98e0b4d 100644 --- a/python/src/bind_core.cpp +++ b/python/src/bind_core.cpp @@ -23,21 +23,10 @@ void odr_python::bind_core(py::module_ &m) { py::class_(m, "GlobalParams", "Global resource paths of the library.") .def_static("odr_core_data_path", &odr::GlobalParams::odr_core_data_path) - .def_static("fontconfig_data_path", - &odr::GlobalParams::fontconfig_data_path) - .def_static("poppler_data_path", &odr::GlobalParams::poppler_data_path) - .def_static("pdf2htmlex_data_path", - &odr::GlobalParams::pdf2htmlex_data_path) .def_static("libmagic_database_path", &odr::GlobalParams::libmagic_database_path) .def_static("set_odr_core_data_path", &odr::GlobalParams::set_odr_core_data_path, py::arg("path")) - .def_static("set_fontconfig_data_path", - &odr::GlobalParams::set_fontconfig_data_path, py::arg("path")) - .def_static("set_poppler_data_path", - &odr::GlobalParams::set_poppler_data_path, py::arg("path")) - .def_static("set_pdf2htmlex_data_path", - &odr::GlobalParams::set_pdf2htmlex_data_path, py::arg("path")) .def_static("set_libmagic_database_path", &odr::GlobalParams::set_libmagic_database_path, py::arg("path")); diff --git a/python/src/bind_file.cpp b/python/src/bind_file.cpp index 781c70612..c67bc9cf3 100644 --- a/python/src/bind_file.cpp +++ b/python/src/bind_file.cpp @@ -68,9 +68,7 @@ void odr_python::bind_file(py::module_ &m) { .value("disk", odr::FileLocation::disk); py::enum_(m, "DecoderEngine") - .value("odr", odr::DecoderEngine::odr) - .value("poppler", odr::DecoderEngine::poppler) - .value("wvware", odr::DecoderEngine::wvware); + .value("odr", odr::DecoderEngine::odr); py::enum_(m, "EncryptionState") .value("unknown", odr::EncryptionState::unknown) diff --git a/scripts/run-with-env.sh b/scripts/run-with-env.sh index 3d951b835..4a5fa8441 100755 --- a/scripts/run-with-env.sh +++ b/scripts/run-with-env.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Load the Conan runtime env from .vscode/.env (see gen-vscode-env.py) and exec # the given command with it. Used by VS Code tasks so the test binary and CLI -# tools can find pdf2htmlEX / poppler / fontconfig / wvWare / libmagic data. +# tools can find the libmagic database. # # Usage: scripts/run-with-env.sh [args...] set -euo pipefail diff --git a/src/odr/file.cpp b/src/odr/file.cpp index 84c863b06..b5a6f1394 100644 --- a/src/odr/file.cpp +++ b/src/odr/file.cpp @@ -23,11 +23,6 @@ DocumentMeta::DocumentMeta(const DocumentType document_type, FileMeta::FileMeta() = default; -FileMeta::FileMeta(const FileType type, const bool password_encrypted, - const std::optional document_meta) - : type{type}, password_encrypted{password_encrypted}, - document_meta{document_meta} {} - FileMeta::FileMeta(const FileType type, const std::string_view mimetype, const bool password_encrypted, const std::optional document_meta) diff --git a/src/odr/file.hpp b/src/odr/file.hpp index 5918172eb..3681533f2 100644 --- a/src/odr/file.hpp +++ b/src/odr/file.hpp @@ -106,8 +106,6 @@ enum class FileLocation { /// @brief Collection of decoder engines. enum class DecoderEngine { odr, - poppler, - wvware, }; /// @brief Preference for decoding files. @@ -160,9 +158,6 @@ struct DocumentMeta final { /// @brief Meta information about a file. struct FileMeta final { FileMeta(); - [[deprecated]] - FileMeta(FileType type, bool password_encrypted, - std::optional document_meta); FileMeta(FileType type, std::string_view mimetype, bool password_encrypted, std::optional document_meta); diff --git a/src/odr/global_params.cpp b/src/odr/global_params.cpp index df9009e14..83983c99c 100644 --- a/src/odr/global_params.cpp +++ b/src/odr/global_params.cpp @@ -2,45 +2,18 @@ #include -#ifdef ODR_WITH_PDF2HTMLEX -#include -#endif - namespace odr { GlobalParams &GlobalParams::instance() { - struct HolderAndInitializer { - GlobalParams params; - HolderAndInitializer() { -#ifdef ODR_WITH_PDF2HTMLEX - globalParams = std::make_unique<::GlobalParams>( - params.m_poppler_data_path.empty() - ? nullptr - : params.m_poppler_data_path.c_str()); -#endif - } - }; - static HolderAndInitializer instance; + static GlobalParams instance; - return instance.params; + return instance; } const std::string &GlobalParams::odr_core_data_path() { return instance().m_odr_core_data_path; } -const std::string &GlobalParams::fontconfig_data_path() { - return instance().m_fontconfig_data_path; -} - -const std::string &GlobalParams::poppler_data_path() { - return instance().m_poppler_data_path; -} - -const std::string &GlobalParams::pdf2htmlex_data_path() { - return instance().m_pdf2htmlex_data_path; -} - const std::string &GlobalParams::libmagic_database_path() { return instance().m_libmagic_database_path; } @@ -49,32 +22,12 @@ void GlobalParams::set_odr_core_data_path(const std::string &path) { instance().m_odr_core_data_path = path; } -void GlobalParams::set_fontconfig_data_path(const std::string &path) { - instance().m_fontconfig_data_path = path; -} - -void GlobalParams::set_poppler_data_path(const std::string &path) { - instance().m_poppler_data_path = path; - -#ifdef ODR_WITH_PDF2HTMLEX - globalParams = - std::make_unique<::GlobalParams>(path.empty() ? nullptr : path.c_str()); -#endif -} - -void GlobalParams::set_pdf2htmlex_data_path(const std::string &path) { - instance().m_pdf2htmlex_data_path = path; -} - void GlobalParams::set_libmagic_database_path(const std::string &path) { instance().m_libmagic_database_path = path; } GlobalParams::GlobalParams() : m_odr_core_data_path{internal::project_info::odr_data_path()}, - m_fontconfig_data_path{internal::project_info::fontconfig_data_path()}, - m_poppler_data_path{internal::project_info::poppler_data_path()}, - m_pdf2htmlex_data_path{internal::project_info::pdf2htmlex_data_path()}, m_libmagic_database_path{ internal::project_info::libmagic_database_path()} {} diff --git a/src/odr/global_params.hpp b/src/odr/global_params.hpp index 66c081790..c53214182 100644 --- a/src/odr/global_params.hpp +++ b/src/odr/global_params.hpp @@ -7,15 +7,9 @@ namespace odr { class GlobalParams final { public: static const std::string &odr_core_data_path(); - static const std::string &fontconfig_data_path(); - static const std::string &poppler_data_path(); - static const std::string &pdf2htmlex_data_path(); static const std::string &libmagic_database_path(); static void set_odr_core_data_path(const std::string &path); - static void set_fontconfig_data_path(const std::string &path); - static void set_poppler_data_path(const std::string &path); - static void set_pdf2htmlex_data_path(const std::string &path); static void set_libmagic_database_path(const std::string &path); private: @@ -24,9 +18,6 @@ class GlobalParams final { GlobalParams(); std::string m_odr_core_data_path; - std::string m_fontconfig_data_path; - std::string m_poppler_data_path; - std::string m_pdf2htmlex_data_path; std::string m_libmagic_database_path; }; diff --git a/src/odr/html.cpp b/src/odr/html.cpp index 4c80d0e34..eb46dec7f 100644 --- a/src/odr/html.cpp +++ b/src/odr/html.cpp @@ -14,12 +14,8 @@ #include #include #include -#include #include #include -#include -#include -#include #include #include @@ -295,20 +291,6 @@ HtmlService html::translate(const DocumentFile &document_file, const std::string &cache_path, const HtmlConfig &config, std::shared_ptr logger) { - const std::shared_ptr document_file_impl = - document_file.impl(); - -#ifdef ODR_WITH_WVWARE - if (const std::shared_ptr wv_document_file = - std::dynamic_pointer_cast( - document_file_impl); - wv_document_file != nullptr) { - std::filesystem::create_directories(cache_path); - return internal::html::create_wvware_oldms_service( - *wv_document_file, cache_path, config, std::move(logger)); - } -#endif - return translate(document_file.document(), cache_path, config, std::move(logger)); } @@ -317,18 +299,6 @@ HtmlService html::translate(const PdfFile &pdf_file, const std::string &cache_path, const HtmlConfig &config, std::shared_ptr logger) { - const std::shared_ptr pdf_file_impl = pdf_file.impl(); - -#ifdef ODR_WITH_PDF2HTMLEX - if (const std::shared_ptr poppler_pdf_file = - std::dynamic_pointer_cast(pdf_file_impl); - poppler_pdf_file != nullptr) { - std::filesystem::create_directories(cache_path); - return internal::html::create_poppler_pdf_service( - *poppler_pdf_file, cache_path, config, std::move(logger)); - } -#endif - return internal::html::create_pdf_service(pdf_file, cache_path, config, std::move(logger)); } diff --git a/src/odr/internal/html/pdf2htmlex_wrapper.cpp b/src/odr/internal/html/pdf2htmlex_wrapper.cpp deleted file mode 100644 index fc938bf3e..000000000 --- a/src/odr/internal/html/pdf2htmlex_wrapper.cpp +++ /dev/null @@ -1,332 +0,0 @@ -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include - -#include - -namespace odr::internal::html { - -namespace { - -pdf2htmlEX::Param create_params(PDFDoc &pdf_doc, const HtmlConfig &config, - const std::string &cache_path) { - pdf2htmlEX::Param param; - - // pages - param.first_page = 1; - param.last_page = pdf_doc.getNumPages(); - - // dimension - param.zoom = 0; - param.fit_width = 0; - param.fit_height = 0; - param.use_cropbox = 1; - param.desired_dpi = config.background_image_dpi; - param.actual_dpi = config.background_image_dpi; - param.max_dpi = config.background_image_dpi; - param.text_dpi = config.background_image_dpi; - - // output - param.embed_css = 1; - param.embed_font = 1; - param.embed_image = 1; - param.embed_javascript = 1; - param.embed_outline = config.embed_outline ? 1 : 0; - param.split_pages = 0; - param.dest_dir = cache_path; - param.css_filename = "style.css"; - param.page_filename = "page%i.html"; - param.outline_filename = "outline.html"; - param.process_nontext = 1; - param.process_outline = 1; - param.process_annotation = 0; - param.process_form = 0; - param.printing = 1; - param.fallback = 0; - param.tmp_file_size_limit = -1; - param.delay_background = 0; - - // font - param.embed_external_font = 0; // TODO 1 - param.font_format = "woff"; - param.decompose_ligature = 0; - param.turn_off_ligatures = 0; - param.auto_hint = 0; - param.external_hint_tool = ""; - param.stretch_narrow_glyph = 0; - param.squeeze_wide_glyph = 1; - param.override_fstype = 0; - param.process_type3 = 0; - - // text - param.h_eps = 1.0; - param.v_eps = 1.0; - param.space_threshold = 1.0 / 8; - param.font_size_multiplier = 4.0; - param.space_as_offset = 0; - param.tounicode = 0; - param.optimize_text = 0; - param.correct_text_visibility = 1; - - // background - param.bg_format = config.background_image_format; - param.svg_node_count_limit = -1; - param.svg_embed_bitmap = 1; - - // encryption - param.owner_password = ""; - param.user_password = ""; - param.no_drm = config.no_drm ? 1 : 0; - - // misc - param.clean_tmp = 1; - param.tmp_dir = cache_path; - param.data_dir = GlobalParams::pdf2htmlex_data_path(); - param.poppler_data_dir = GlobalParams::poppler_data_path(); - param.debug = 0; - param.proof = 0; - param.quiet = 1; - - // input, output - param.input_filename = ""; - param.output_filename = "document.html"; - - return param; -} - -} // namespace - -class BackgroundImageResource final : public HtmlResource { -public: - static std::string file_name(const std::size_t page_number) { - std::stringstream stream; - stream << "bg"; - stream << std::hex << page_number; - return stream.str(); - } - - static std::string file_path(const std::size_t page_number, - const std::string &format) { - std::stringstream stream; - stream << "bg"; - stream << std::hex << page_number; - stream << "." << format; - return stream.str(); - } - - BackgroundImageResource( - PopplerPdfFile pdf_file, std::string cache_path, - std::shared_ptr html_renderer, - std::shared_ptr html_renderer_mutex, - std::shared_ptr html_renderer_param, - const int page_number, const std::string &format) - : HtmlResource(HtmlResourceType::image, "image/jpg", - file_name(page_number), file_path(page_number, format), - std::nullopt, false, false, true), - m_pdf_file{std::move(pdf_file)}, m_cache_path{std::move(cache_path)}, - m_html_renderer{std::move(html_renderer)}, - m_html_renderer_mutex{std::move(html_renderer_mutex)}, - m_html_renderer_param{std::move(html_renderer_param)}, - m_page_number{page_number} {} - - std::string disk_path() const { return m_cache_path + "/" + path(); } - - void warmup() const { - std::lock_guard lock(m_mutex); - - if (std::filesystem::exists(disk_path())) { - return; - } - - std::lock_guard renderer_lock(*m_html_renderer_mutex); - PDFDoc &pdf_doc = m_pdf_file.pdf_doc(); - m_html_renderer->renderPage(&pdf_doc, m_page_number); - } - - void write_resource(std::ostream &os) const override { - warmup(); - - util::file::pipe(disk_path(), os); - } - -private: - PopplerPdfFile m_pdf_file; - std::string m_cache_path; - std::shared_ptr m_html_renderer; - std::shared_ptr m_html_renderer_mutex; - std::shared_ptr m_html_renderer_param; - int m_page_number; - mutable std::mutex m_mutex; -}; - -class HtmlServiceImpl final : public HtmlService { -public: - HtmlServiceImpl(PopplerPdfFile pdf_file, std::string cache_path, - std::shared_ptr html_renderer, - std::shared_ptr html_renderer_mutex, - std::shared_ptr html_renderer_param, - HtmlConfig config, std::shared_ptr logger) - : HtmlService(std::move(config), std::move(logger)), - m_pdf_file{std::move(pdf_file)}, m_cache_path{std::move(cache_path)}, - m_html_renderer{std::move(html_renderer)}, - m_html_renderer_mutex{std::move(html_renderer_mutex)}, - m_html_renderer_param{std::move(html_renderer_param)} { - m_views.emplace_back( - std::make_shared(*this, "document", 0, "document.html")); - } - - const HtmlViews &list_views() const override { return m_views; } - - void warmup() const override { - if (m_warm) { - return; - } - - for (int i = 1; i <= m_pdf_file.pdf_doc().getNumPages(); ++i) { - auto resource = - odr::HtmlResource(std::make_shared( - m_pdf_file, m_cache_path, m_html_renderer, m_html_renderer_mutex, - m_html_renderer_param, i, m_html_renderer_param->bg_format)); - // not calling the resource locator since these cannot be relocated - HtmlResourceLocation location = - config().embed_images ? HtmlResourceLocation() : resource.path(); - m_resources.emplace_back(std::move(resource), std::move(location)); - } - - m_warm = true; - } - - bool exists(const std::string &path) const override { - if (std::ranges::any_of(m_views, [&path](const auto &view) { - return view.path() == path; - })) { - return true; - } - - if (std::ranges::any_of(m_resources, [&path](const auto &pair) { - const auto &[resource, location] = pair; - return location.has_value() && location.value() == path; - })) { - return true; - } - - return false; - } - - std::string mimetype(const std::string &path) const override { - if (std::ranges::any_of(m_views, [&path](const auto &view) { - return view.path() == path; - })) { - return "text/html"; - } - - for (const auto &[resource, location] : m_resources) { - if (location.has_value() && location.value() == path) { - return resource.mime_type(); - } - } - - throw FileNotFound("Unknown path: " + path); - } - - HtmlResources write_document(HtmlWriter &out) const { - warmup(); - - util::file::pipe(m_cache_path + "/document.html", out.out()); - - return m_resources; - } - - void write(const std::string &path, std::ostream &out) const override { - warmup(); - - for (const auto &view : m_views) { - if (view.path() == path) { - HtmlWriter writer(out, config()); - write_html(path, writer); - return; - } - } - - for (const auto &[resource, location] : m_resources) { - if (location.has_value() && location.value() == path) { - resource.write_resource(out); - return; - } - } - - throw FileNotFound("Unknown path: " + path); - } - - HtmlResources write_html(const std::string &path, - HtmlWriter &out) const override { - if (path == "document.html") { - return write_document(out); - } - - throw FileNotFound("Unknown path: " + path); - } - -private: - PopplerPdfFile m_pdf_file; - std::string m_cache_path; - std::shared_ptr m_html_renderer; - std::shared_ptr m_html_renderer_mutex; - std::shared_ptr m_html_renderer_param; - - HtmlViews m_views; - - mutable bool m_warm = false; - mutable HtmlResources m_resources; -}; - -} // namespace odr::internal::html - -namespace odr::internal { - -HtmlService html::create_poppler_pdf_service(const PopplerPdfFile &pdf_file, - const std::string &cache_path, - HtmlConfig config, - std::shared_ptr logger) { - PDFDoc &pdf_doc = pdf_file.pdf_doc(); - - auto html_renderer_param = std::make_shared( - create_params(pdf_doc, config, cache_path)); - if (config.embed_images) { - html_renderer_param->embed_image = 1; - html_renderer_param->delay_background = 0; - } else { - html_renderer_param->embed_image = 0; - html_renderer_param->delay_background = 1; - } - - // TODO not sure what the `progPath` is used for. it cannot be `nullptr` - // TODO potentially just a cache dir? - auto html_renderer = std::make_shared( - GlobalParams::fontconfig_data_path().c_str(), *html_renderer_param); - html_renderer->process(&pdf_doc); - - // renderer is not thread safe - // TODO check if this can be achieved in pdf2htmlEX - auto html_renderer_mutex = std::make_shared(); - - return odr::HtmlService(std::make_shared( - pdf_file, cache_path, std::move(html_renderer), - std::move(html_renderer_mutex), std::move(html_renderer_param), - std::move(config), std::move(logger))); -} - -} // namespace odr::internal diff --git a/src/odr/internal/html/pdf2htmlex_wrapper.hpp b/src/odr/internal/html/pdf2htmlex_wrapper.hpp deleted file mode 100644 index 038df2726..000000000 --- a/src/odr/internal/html/pdf2htmlex_wrapper.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include - -namespace odr { -struct HtmlConfig; -class Html; -class HtmlService; -class Logger; -} // namespace odr - -namespace odr::internal { -class PopplerPdfFile; -} // namespace odr::internal - -namespace odr::internal::html { - -HtmlService create_poppler_pdf_service(const PopplerPdfFile &pdf_file, - const std::string &cache_path, - HtmlConfig config, - std::shared_ptr logger); - -} // namespace odr::internal::html diff --git a/src/odr/internal/html/wvware_wrapper.cpp b/src/odr/internal/html/wvware_wrapper.cpp deleted file mode 100644 index 5c7c8d751..000000000 --- a/src/odr/internal/html/wvware_wrapper.cpp +++ /dev/null @@ -1,984 +0,0 @@ -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -namespace odr::internal::html { - -/// A lot of this code is duplicated from wvWare, mostly from `wvWare.c` and -/// `wvHtml.c`. -/// -/// wvWare is writing to stdout, while we want to write to a file. Also, wvWare -/// is configurable to write not only HTML but also other formats. We only need -/// HTML. -/// -/// We decided to duplicate the code instead of changing upstream wvWare code -/// because it is rather an application not a library, it is quite outdated and -/// not actively developed, and written in C. Duplication allows for a clean -/// separation between wvWare and our code while also being able to write modern -/// C++ code. -/// -/// A copy of wvWare can be found here: -/// https://github.com/opendocument-app/wvWare -namespace { - -/// Extension of `expand_data` see -/// https://github.com/opendocument-app/wvWare/blob/c015326b001f1ad6dfb1f5e718461c16c56cca5f/wv.h#L2776-L2814 -/// to allow for more state variables. -struct TranslationState : expand_data { - explicit TranslationState(HtmlWriter _out, HtmlResources &_resources, - const HtmlConfig &_config, std::string _cache_path) - : expand_data{}, out(std::move(_out)), resources(&_resources), - config{&_config}, cache_path{std::move(_cache_path)} {} - - char *charset = nullptr; - PAP *ppap = nullptr; - - struct { - int message = 0; - } special_char_handler_state = {}; - - std::size_t figure_number = 0; - - HtmlWriter out; - HtmlResources *resources; - const HtmlConfig *config; - std::string cache_path; -}; - -std::string figure_name(const wvParseStruct *ps) { - auto *data = static_cast(ps->userData); - - const std::size_t number = data->figure_number++; - std::string name = "figure" + std::to_string(number); - - return name; -} - -std::string figure_cache_path(const wvParseStruct *ps, - const std::string &name) { - const auto *data = static_cast(ps->userData); - - return data->cache_path + "/" + name; -} - -/// Originally from `text.c` `wvConvertUnicodeToHtml` -/// https://github.com/opendocument-app/wvWare/blob/c015326b001f1ad6dfb1f5e718461c16c56cca5f/text.c#L1999-L2154 -int convert_unicode_to_html(const wvParseStruct *ps, - const std::uint16_t char16) { - auto *data = static_cast(ps->userData); - auto &out = data->out; - - switch (char16) { - case 11: - out.out() << "
"; - return 1; - case 31: /* non-required hyphen */ - out.out() << "­"; /*vladimir@lukianov.name HTML 4.01 spec*/ - return 1; - case 30: - case 45: - case 0x2013: - out.out() << "-"; /* en-dash */ - return 1; - case 12: - case 13: - case 14: - case 7: - return 1; - case 34: - out.out() << """; - return 1; - case 38: - out.out() << "&"; - return 1; - case 60: - out.out() << "<"; - return 1; - case 62: - out.out() << ">"; - return 1; - /* - german characters, im assured that this is the right way to handle them - by Markus Schulte - - As the output encoding for HTML was chosen as UTF-8, - we don't need Ä etc. etc. I removed all but sz - -- MV 6.4.2000 - */ - - case 0xdf: - out.out() << "ß"; - return 1; - /* end german characters */ - case 0x2026: - out.out() << "…"; - return 1; - case 0x2019: - out.out() << "'"; - return 1; - case 0x2215: - out.out() << "/"; - return 1; - case 0xF8E7: /* without this, things should work in theory, but not for me */ - out.out() << "_"; - return 1; - case 0x2018: - out.out() << "`"; - return 1; - - /* Windows specials (MV): */ - case 0x0160: - out.out() << "Š"; - return 1; - case 0x0161: - out.out() << "š"; - return 1; - case 0x2014: - out.out() << "—"; - return 1; - case 0x201c: - out.out() << "“"; /* inverted double quotation mark */ - return 1; - case 0x201d: - out.out() << "”"; /* double q.m. */ - return 1; - case 0x201e: - out.out() << "„"; /* below double q.m. */ - return 1; - case 0x2020: - out.out() << "†"; - return 1; - case 0x2021: - out.out() << "‡"; - return 1; - case 0x2022: - out.out() << "•"; - return 1; - case 0x0152: - out.out() << "Œ"; - return 1; - case 0x0153: - out.out() << "œ"; - return 1; - case 0x0178: - out.out() << "Ÿ"; - return 1; - case 0x2030: - out.out() << "‰"; - return 1; - case 0x20ac: - out.out() << "€"; - return 1; - - /* Mac specials (MV): */ - case 0xf020: - out.out() << " "; - return 1; - case 0xf02c: - out.out() << ","; - return 1; - case 0xf028: - out.out() << "("; - return 1; - - case 0xf03e: - out.out() << ">"; - return 1; - case 0xf067: - out.out() << "γ"; - return 1; - case 0xf064: - out.out() << "δ"; - return 1; - case 0xf072: - out.out() << "ρ"; - return 1; - case 0xf073: - out.out() << "σ"; - return 1; - case 0xf0ae: - out.out() << "→"; /* right arrow */ - return 1; - case 0xf0b6: - out.out() << "∂"; /* partial deriv. */ - return 1; - case 0xf0b3: - out.out() << "≥"; - return 1; - default: - break; - } - return 0; -} - -/// Originally from `text.c` `wvOutputFromUnicode` -/// https://github.com/opendocument-app/wvWare/blob/c015326b001f1ad6dfb1f5e718461c16c56cca5f/text.c#L757-L840 -void output_from_unicode(const wvParseStruct *ps, const std::uint16_t eachchar, - const char *outputtype) { - auto *data = static_cast(ps->userData); - HtmlWriter &out = data->out; - - GIConv g_iconv_handle{}; - int need_swapping{}; - gchar *ibuf{}, *obuf{}; - std::size_t ibuflen{}, obuflen{}, len{}, count{}, i{}; - std::uint8_t buffer[2], buffer2[5]; - - if (convert_unicode_to_html(ps, eachchar) != 0) { - return; - } - - { - g_iconv_handle = g_iconv_open(outputtype, "UCS-2"); - // (GIConv)-1 is glib's documented error value - // NOLINTNEXTLINE(performance-no-int-to-ptr) - if (g_iconv_handle == reinterpret_cast(-1)) { - std::cerr << "g_iconv_open fail: " << errno - << ", cannot convert UCS-2 to " << outputtype << "\n"; - out.out() << "?"; - return; - } - - /* Determining if unicode biteorder is swapped (glibc < 2.2) */ - need_swapping = 1; - - buffer[0] = 0x20; - buffer[1] = 0; - ibuf = reinterpret_cast(buffer); - obuf = reinterpret_cast(buffer2); - ibuflen = 2; - obuflen = 5; - - count = g_iconv(g_iconv_handle, &ibuf, &ibuflen, &obuf, &obuflen); - if (count != static_cast(-1)) { - need_swapping = buffer2[0] != 0x20; - } - } - - if (need_swapping) { - buffer[0] = (eachchar >> 8) & 0x00ff; - buffer[1] = eachchar & 0x00ff; - } else { - buffer[0] = eachchar & 0x00ff; - buffer[1] = (eachchar >> 8) & 0x00ff; - } - - ibuf = reinterpret_cast(buffer); - obuf = reinterpret_cast(buffer2); - - ibuflen = 2; - len = obuflen = 5; - - count = g_iconv(g_iconv_handle, &ibuf, &ibuflen, &obuf, &obuflen); - if (count == (std::size_t)-1) { - std::cerr << "iconv failed, errno: " << errno << ", char: 0x" << std::hex - << eachchar << ", UCS-2 -> " << outputtype << "\n"; - - /* I'm torn here - do i just announce the failure, continue, or copy over to - * the other buffer? */ - - /* errno is usually 84 (illegal byte sequence) - should i reverse the bytes and try again? */ - out.out() << ibuf[1]; - } else { - len = len - obuflen; - - for (i = 0; i < len; i++) { - out.out() << buffer2[i]; - } - } - - // TODO iconv could be cached - g_iconv_close(g_iconv_handle); -} - -/// Originally from `wvWare.c` `wvStrangeNoGraphicData` -/// https://github.com/opendocument-app/wvWare/blob/c015326b001f1ad6dfb1f5e718461c16c56cca5f/wvWare.c#L661-L676 -/// simplified to HTML output -void strange_no_graphic_data(wvParseStruct *ps, int graphicstype) { - auto *data = static_cast(ps->userData); - auto &out = data->out; - - std::cerr << "Strange No Graphic Data in the 0x01/0x08 graphic\n"; - - // TODO - out.out() << R"()
)"; -} - -/// Originally from `wvWare.c` `wvPrintGraphics` -/// https://github.com/opendocument-app/wvWare/blob/c015326b001f1ad6dfb1f5e718461c16c56cca5f/wvWare.c#L1239-L1287 -/// simplified to HTML output -void print_graphics(wvParseStruct *ps, int /*graphicstype*/, int width, - int height, const std::string &name) { - // upstream converts to PNG, we just use the original format as the browser - // should support them - - auto *data = static_cast(ps->userData); - auto &out = data->out; - - std::string path = figure_cache_path(ps, name); - - File file(path); - odr::HtmlResource resource = - HtmlResource::create(HtmlResourceType::image, "image/jpg", name, name, - file, false, false, true); - HtmlResourceLocation resource_location = - data->config->resource_locator(resource, *data->config); - data->resources->emplace_back(std::move(resource), resource_location); - - out.write_element_begin( - "img", HtmlElementOptions() - .set_close_type(HtmlCloseType::trailing) - .set_attributes([&](const HtmlAttributeWriterCallback &clb) { - clb("alt", "Error: image not found or unsupported"); - if (resource_location.has_value()) { - clb("src", resource_location.value()); - } else { - clb("src", [&](std::ostream &o) { - translate_image_src(file, o, *data->config); - }); - } - }) - .set_style("width:" + std::to_string(width) + - "px;height:" + std::to_string(height) + "px")); - out.write_element_begin( - "br", HtmlElementOptions().set_close_type(HtmlCloseType::trailing)); -} - -void dump_bitmap(wvParseStruct *ps, const std::string &name, - BitmapBlip *bitmap) { - std::string path = figure_cache_path(ps, name); - - wvStream *pwv = bitmap->m_pvBits; - std::size_t size = wvStream_size(pwv); - wvStream_rewind(pwv); - - std::ofstream bitmap_out(path, std::ios::binary); - if (bitmap_out.fail()) { - throw std::runtime_error("Cannot open " + path + " file for writing"); - } - - for (std::size_t i = 0; i < size; i++) { - std::uint8_t byte = read_8ubit(pwv); - bitmap_out.put(static_cast(byte)); - } -} - -int dump_metafile(wvParseStruct *ps, const std::string &name, - MetaFileBlip *bitmap) { - std::string path = figure_cache_path(ps, name); - - FILE *fd = fopen(path.c_str(), "wb"); - if (fd == nullptr) { - throw std::runtime_error("Cannot open " + path + " file for writing"); - } - - wvStream *pwv = bitmap->m_pvBits; - std::size_t size = wvStream_size(pwv); - wvStream_rewind(pwv); - - std::uint8_t decompressf = 0; - if (bitmap->m_fCompression == msocompressionDeflate) { - decompressf = setdecom(); - } - - if (decompressf == 0) { - for (std::size_t i = 0; i < size; i++) { - fputc(read_8ubit(pwv), fd); - } - } else { - FILE *tmp = tmpfile(); - FILE *out = tmpfile(); - - for (std::size_t i = 0; i < size; i++) { - fputc(read_8ubit(pwv), tmp); - } - - fseek(tmp, 0, SEEK_SET); - decompress(tmp, out, bitmap->m_cbSave, bitmap->m_cb); - fclose(tmp); - - fseek(out, 0, SEEK_SET); - - for (std::size_t i = 0; i < bitmap->m_cb; i++) { - fputc(fgetc(out), fd); - } - - fclose(out); - } - - fclose(fd); - return 0; -} - -std::string html_graphic(wvParseStruct *ps, Blip *blip) { - std::string name = figure_name(ps); - - /* - temp hack to test older included bmps in word 6 and 7, - should be wrapped in a modern escher strucure before getting - to here, and then handled as normal - */ - switch (blip->type) { - case msoblipJPEG: - case msoblipDIB: - case msoblipPNG: { - wvStream *fd = (blip->blip.bitmap.m_pvBits); - char test[3]; - test[0] = static_cast(read_8ubit(fd)); - test[1] = static_cast(read_8ubit(fd)); - test[2] = '\0'; - wvStream_rewind(fd); - if (strcmp(test, "BM") == 0) { - name += ".bmp"; - dump_bitmap(ps, name, &blip->blip.bitmap); - return name; - } - } - default: - break; - } - - switch (blip->type) { - case msoblipWMF: - name += ".wmf"; - dump_metafile(ps, name, &blip->blip.metafile); - break; - case msoblipEMF: - name += ".emf"; - dump_metafile(ps, name, &blip->blip.metafile); - break; - case msoblipPICT: - name += ".pict"; - dump_metafile(ps, name, &blip->blip.metafile); - break; - case msoblipJPEG: - name += ".jpg"; - dump_bitmap(ps, name, &blip->blip.bitmap); - break; - case msoblipDIB: - name += ".dib"; - dump_bitmap(ps, name, &blip->blip.bitmap); - break; - case msoblipPNG: - name += ".png"; - dump_bitmap(ps, name, &blip->blip.bitmap); - break; - default: - break; - } - - return name; -} - -/// Originally from `wvWare.c` `myelehandler` -/// https://github.com/opendocument-app/wvWare/blob/c015326b001f1ad6dfb1f5e718461c16c56cca5f/wvWare.c#L503-L599 -int element_handler(wvParseStruct *ps, wvTag tag, void *props, int /*dirty*/) { - auto *data = static_cast(ps->userData); - data->anSttbfAssoc = &ps->anSttbfAssoc; - data->lfo = &ps->lfo; - data->lfolvl = ps->lfolvl; - data->lvl = ps->lvl; - data->nolfo = &ps->nolfo; - data->nooflvl = &ps->nooflvl; - data->stsh = &ps->stsh; - data->lst = &ps->lst; - data->noofLST = &ps->noofLST; - data->liststartnos = &ps->liststartnos; - data->listnfcs = &ps->listnfcs; - data->finallvl = &ps->finallvl; - data->fib = &ps->fib; - data->dop = &ps->dop; - data->intable = &ps->intable; - data->cellbounds = &ps->cellbounds; - data->nocellbounds = &ps->nocellbounds; - data->endcell = &ps->endcell; - data->vmerges = &ps->vmerges; - data->norows = &ps->norows; - data->nextpap = &ps->nextpap; - if (data->charset == nullptr) { - data->charset = wvAutoCharset(ps); - } - data->props = props; - - switch (tag) { - case PARABEGIN: { - S16 tilfo = 0; - /* test begin */ - if (*(data->endcell) != 0) { - tilfo = ((PAP *)(data->props))->ilfo; - ((PAP *)(data->props))->ilfo = 0; - } - /* test end */ - data->ppap = (PAP *)data->props; - wvBeginPara(data); - if (tilfo != 0) { - ((PAP *)(data->props))->ilfo = tilfo; - } - } break; - case PARAEND: { - S16 tilfo = 0; - /* test begin */ - if (*(data->endcell) != 0) { - tilfo = ((PAP *)(data->props))->ilfo; - ((PAP *)(data->props))->ilfo = 0; - } - /* test end */ - wvEndCharProp(data); /* danger will break in the future */ - wvEndPara(data); - if (tilfo != 0) { - ((PAP *)(data->props))->ilfo = tilfo; - } - wvCopyPAP(&data->lastpap, (PAP *)(data->props)); - } break; - case CHARPROPBEGIN: - wvBeginCharProp(data, data->ppap); - break; - case CHARPROPEND: - wvEndCharProp(data); - break; - case SECTIONBEGIN: - wvBeginSection(data); - break; - case SECTIONEND: - wvEndSection(data); - break; - case COMMENTBEGIN: - wvBeginComment(data); - break; - case COMMENTEND: - wvEndComment(data); - break; - default: - break; - } - return 0; -} - -/// Originally from `wvWare.c` `mydochandler` -/// https://github.com/opendocument-app/wvWare/blob/c015326b001f1ad6dfb1f5e718461c16c56cca5f/wvWare.c#L601-L659 -int document_handler(wvParseStruct *ps, wvTag tag) { - auto *data = static_cast(ps->userData); - data->anSttbfAssoc = &ps->anSttbfAssoc; - data->lfo = &ps->lfo; - data->lfolvl = ps->lfolvl; - data->lvl = ps->lvl; - data->nolfo = &ps->nolfo; - data->nooflvl = &ps->nooflvl; - data->stsh = &ps->stsh; - data->lst = &ps->lst; - data->noofLST = &ps->noofLST; - data->liststartnos = &ps->liststartnos; - data->listnfcs = &ps->listnfcs; - data->finallvl = &ps->finallvl; - data->fib = &ps->fib; - data->dop = &ps->dop; - data->intable = &ps->intable; - data->cellbounds = &ps->cellbounds; - data->nocellbounds = &ps->nocellbounds; - data->endcell = &ps->endcell; - data->vmerges = &ps->vmerges; - data->norows = &ps->norows; - - wvSetEntityConverter(data); - data->filename = ps->filename; - data->whichcell = 0; - data->whichrow = 0; - data->asep = nullptr; - wvInitPAP(&data->lastpap); - data->nextpap = nullptr; - data->ps = ps; - - if (data->charset == nullptr) { - data->charset = wvAutoCharset(ps); - } - - switch (tag) { - case DOCBEGIN: - wvBeginDocument(data); - break; - case DOCEND: - wvEndDocument(data); - break; - default: - break; - } - - return 0; -} - -/// Originally from `wvWare.c` `myCharProc` -/// https://github.com/opendocument-app/wvWare/blob/c015326b001f1ad6dfb1f5e718461c16c56cca5f/wvWare.c#L1556-L1605 -int char_handler(wvParseStruct *ps, std::uint16_t eachchar, - const std::uint8_t chartype, const std::uint16_t lid) { - const auto *data = static_cast(ps->userData); - - switch (eachchar) { - case 19: - ps->fieldstate++; - ps->fieldmiddle = 0; - fieldCharProc(ps, eachchar, chartype, lid); /* temp */ - return 0; - case 20: - fieldCharProc(ps, eachchar, chartype, lid); - ps->fieldmiddle = 1; - return 0; - case 21: - ps->fieldmiddle = 0; - ps->fieldstate--; - fieldCharProc(ps, eachchar, chartype, lid); /* temp */ - return 0; - case 0x08: - std::cerr << "hmm did we loose the fSpec flag ?, this is possibly a bug\n"; - break; - default: - break; - } - - if (ps->fieldstate != 0 && fieldCharProc(ps, eachchar, chartype, lid) != 0) { - return 0; - } - - // from `wvOutputHtmlChar` - { - char *outputtype = - data->charset != nullptr ? data->charset : wvAutoCharset(ps); - if (chartype != 0) { - eachchar = wvHandleCodePage(eachchar, lid); - } - output_from_unicode(ps, eachchar, outputtype); - } - - return 0; -} - -/// Originally from `wvWare.c` `mySpecCharProc` -/// https://github.com/opendocument-app/wvWare/blob/c015326b001f1ad6dfb1f5e718461c16c56cca5f/wvWare.c#L1289-L1553 -int special_char_handler(wvParseStruct *ps, std::uint16_t eachchar, CHP *achp) { - auto *data = static_cast(ps->userData); - auto &state = data->special_char_handler_state; - auto &out = data->out; - - PICF picf{}; - FSPA *fspa = nullptr; - - switch (eachchar) { - case 19: - // field began - ps->fieldstate++; - ps->fieldmiddle = 0; - fieldCharProc(ps, eachchar, 0, 0x400); /* temp */ - return 0; - case 20: - if (achp->fOle2 != 0) { - std::cerr << "this field has an associated embedded object of id " - << achp->fcPic_fcObj_lTagObj << "\n"; - } - fieldCharProc(ps, eachchar, 0, 0x400); /* temp */ - ps->fieldmiddle = 1; - return 0; - case 21: - ps->fieldstate--; - ps->fieldmiddle = 0; - fieldCharProc(ps, eachchar, 0, 0x400); /* temp */ - return 0; - default: - break; - } - - if (ps->fieldstate) { - if (fieldCharProc(ps, eachchar, 0, 0x400)) - return 0; - } - - switch (eachchar) { - case 0x05: - /* this should be handled by the COMMENTBEGIN and COMMENTEND events */ - return 0; - case 0x01: { - wvStream *f; - Blip blip; - long p = wvStream_tell(ps->data); - - if (achp->fOle2 != 0) { - return 0; - } - - wvStream_goto(ps->data, achp->fcPic_fcObj_lTagObj); - wvGetPICF(wvQuerySupported(&ps->fib, nullptr), &picf, ps->data); - f = picf.rgb; - if (wv0x01(&blip, f, picf.lcb - picf.cbHeader) != 0) { - std::string name = html_graphic(ps, &blip); - print_graphics(ps, 0x01, static_cast(wvTwipsToHPixels(picf.dxaGoal)), - static_cast(wvTwipsToVPixels(picf.dyaGoal)), name); - } else { - strange_no_graphic_data(ps, 0x01); - } - - wvStream_goto(ps->data, p); - return 0; - } - case 0x08: { - Blip blip; - if (wvQuerySupported(&ps->fib, nullptr) == WORD8) { - if (ps->nooffspa > 0) { - fspa = - wvGetFSPAFromCP(ps->currentcp, ps->fspa, ps->fspapos, ps->nooffspa); - - if (fspa == nullptr) { - std::cerr << "No fspa! Insanity abounds!\n"; - return 0; - } - - data->props = fspa; - if (wv0x08(&blip, static_cast(fspa->spid), ps) != 0) { - std::string name = html_graphic(ps, &blip); - print_graphics(ps, 0x08, - static_cast(wvTwipsToHPixels( - static_cast(fspa->xaRight - fspa->xaLeft))), - static_cast(wvTwipsToVPixels( - static_cast(fspa->yaBottom - fspa->yaTop))), - name); - } else { - strange_no_graphic_data(ps, 0x08); - } - } else { - std::cerr << "nooffspa was <=0! Ignoring.\n"; - } - } else { - std::cerr << "pre word8 0x08 graphic, unsupported at the moment\n"; - FDOA *fdoa = - wvGetFDOAFromCP(ps->currentcp, ps->fdoa, ps->fdoapos, ps->nooffdoa); - data->props = fdoa; - } - - // Potentially relevant disabled code section in `wvWare.c`? - // https://github.com/opendocument-app/wvWare/blob/c015326b001f1ad6dfb1f5e718461c16c56cca5f/wvWare.c#L1443-L1459 - - return 0; - } - case 0x28: { - std::uint16_t symbol[6] = {'S', 'y', 'm', 'b', 'o', 'l'}; - std::uint16_t wingdings[9] = {'W', 'i', 'n', 'g', 'd', 'i', 'n', 'g', 's'}; - std::uint16_t mtextra[8] = {'M', 'T', ' ', 'E', 'x', 't', 'r', 'a'}; - - if (memcmp(symbol, ps->fonts.ffn[achp->ftcSym].xszFfn, 12) == 0) { - if (state.message == 0 && strcasecmp("UTF-8", data->charset) != 0) { - std::cerr << "Symbol font detected (too late sorry!), rerun wvHtml " - "with option --charset utf-8\noption to support correct " - "symbol font conversion to a viewable format.\n"; - state.message++; - } - output_from_unicode(ps, wvConvertSymbolToUnicode(achp->xchSym - 61440), - data->charset); - return 0; - } - if (memcmp(mtextra, ps->fonts.ffn[achp->ftcSym].xszFfn, 16) == 0) { - if (state.message == 0 && strcasecmp("UTF-8", data->charset) != 0) { - std::cerr - << "MT Extra font detected (too late sorry!), rerun wvHtml with option --charset utf-8\n\ -option to support correct symbol font conversion to a viewable format.\n"; - state.message++; - } - output_from_unicode(ps, wvConvertMTExtraToUnicode(achp->xchSym - 61440), - data->charset); - return 0; - } - if (memcmp(wingdings, ps->fonts.ffn[achp->ftcSym].xszFfn, 18) == 0) { - if (state.message == 0) { - std::cerr << "Wingdings font detected, i need a mapping table to " - "unicode for this\n"; - state.message++; - } - } else { - if (state.message == 0) { - char *fontname = wvWideStrToMB(ps->fonts.ffn[achp->ftcSym].xszFfn); - std::cerr << "Special font " << fontname - << ", I need a mapping table to unicode for this\n"; - wvFree(fontname); - out.out() << "*"; - state.message++; - } - return 0; - } - } - default: - break; - } - - return 0; -} - -class HtmlServiceImpl final : public HtmlService { -public: - HtmlServiceImpl(WvWareLegacyMicrosoftFile oldms_file, HtmlConfig config, - std::string cache_path, std::shared_ptr logger) - : HtmlService(std::move(config), std::move(logger)), - m_oldms_file{std::move(oldms_file)}, - m_cache_path{std::move(cache_path)} { - m_views.emplace_back( - std::make_shared(*this, "document", 0, "document.html")); - } - - [[nodiscard]] const HtmlViews &list_views() const override { return m_views; } - - void warmup() const override { - std::lock_guard lock(m_mutex); - - if (m_warm) { - return; - } - - std::ofstream document_out(m_cache_path + "/document.html"); - HtmlWriter out(document_out, config()); - m_resources = write_document(out); - - m_warm = true; - } - - bool exists(const std::string &path) const override { - if (std::ranges::any_of(m_views, [&path](const auto &view) { - return view.path() == path; - })) { - return true; - } - - warmup(); - - if (std::ranges::any_of(m_resources, [&path](const auto &pair) { - const auto &[resource, location] = pair; - return location.has_value() && location.value() == path; - })) { - return true; - } - - return false; - } - - std::string mimetype(const std::string &path) const override { - if (std::ranges::any_of(m_views, [&path](const auto &view) { - return view.path() == path; - })) { - return "text/html"; - } - - warmup(); - - for (const auto &[resource, location] : m_resources) { - if (location.has_value() && location.value() == path) { - return resource.mime_type(); - } - } - - throw FileNotFound("Unknown path: " + path); - } - - void write(const std::string &path, std::ostream &out) const override { - for (const auto &view : m_views) { - if (view.path() == path) { - HtmlWriter writer(out, config()); - write_html(path, writer); - return; - } - } - - warmup(); - - for (const auto &[resource, location] : m_resources) { - if (location.has_value() && location.value() == path) { - resource.write_resource(out); - return; - } - } - - throw FileNotFound("Unknown path: " + path); - } - - HtmlResources write_html(const std::string &path, - HtmlWriter &out) const override { - warmup(); - - util::file::pipe(m_cache_path + "/" + path, out.out()); - - return m_resources; - } - - HtmlResources write_document(HtmlWriter &out) const { - HtmlResources resources; - - wvParseStruct &ps = m_oldms_file.parse_struct(); - - wvSetElementHandler(&ps, element_handler); - wvSetDocumentHandler(&ps, document_handler); - wvSetCharHandler(&ps, char_handler); - wvSetSpecialCharHandler(&ps, special_char_handler); - - state_data handle; - TranslationState translation_state(out, resources, config(), m_cache_path); - - wvInitStateData(&handle); - - translation_state.sd = &handle; - ps.userData = &translation_state; - - out.write_begin(); - out.write_header_begin(); - out.write_header_charset("UTF-8"); - out.write_header_target("_blank"); - out.write_header_title("odr"); - write_viewport_meta(out, config(), false); - out.write_header_end(); - out.write_body_begin(); - - if (wvHtml(&ps) != 0) { - throw std::runtime_error("wvHtml failed"); - } - - out.write_body_end(); - out.write_end(); - - return resources; - } - -protected: - WvWareLegacyMicrosoftFile m_oldms_file; - - std::string m_cache_path; - - HtmlViews m_views; - - mutable std::mutex m_mutex; - mutable bool m_warm = false; - mutable HtmlResources m_resources; -}; - -} // namespace -} // namespace odr::internal::html - -namespace odr::internal { - -HtmlService html::create_wvware_oldms_service( - const WvWareLegacyMicrosoftFile &oldms_file, const std::string &cache_path, - HtmlConfig config, std::shared_ptr logger) { - return odr::HtmlService(std::make_unique( - oldms_file, std::move(config), cache_path, std::move(logger))); -} - -} // namespace odr::internal diff --git a/src/odr/internal/html/wvware_wrapper.hpp b/src/odr/internal/html/wvware_wrapper.hpp deleted file mode 100644 index 35fe00b67..000000000 --- a/src/odr/internal/html/wvware_wrapper.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include -#include - -namespace odr { -struct HtmlConfig; -class HtmlService; -class Logger; -} // namespace odr - -namespace odr::internal { -class WvWareLegacyMicrosoftFile; -} // namespace odr::internal - -namespace odr::internal::html { - -HtmlService -create_wvware_oldms_service(const WvWareLegacyMicrosoftFile &oldms_file, - const std::string &cache_path, HtmlConfig config, - std::shared_ptr logger); - -} diff --git a/src/odr/internal/oldms_wvware/wvware_oldms_file.cpp b/src/odr/internal/oldms_wvware/wvware_oldms_file.cpp deleted file mode 100644 index 2ff7a810e..000000000 --- a/src/odr/internal/oldms_wvware/wvware_oldms_file.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include - -#include - -#include - -#include -#include -#include - -namespace odr::internal { - -struct WvWareLegacyMicrosoftFile::ParserState { - GsfInput *gsf_input{}; - - wvParseStruct ps{}; - int encryption_flag{}; - - ~ParserState() { wvOLEFree(&ps); } -}; - -WvWareLegacyMicrosoftFile::WvWareLegacyMicrosoftFile( - std::shared_ptr file) - : m_file{std::move(file)} { - GError *error = nullptr; - - m_parser_state = std::make_shared(); - - if (const std::optional disk_path = m_file->disk_path(); - disk_path.has_value()) { - m_parser_state->gsf_input = - gsf_input_stdio_new(disk_path->string().c_str(), &error); - } else if (m_file->memory_data() != nullptr) { - m_parser_state->gsf_input = gsf_input_memory_new( - reinterpret_cast(m_file->memory_data()), - static_cast(m_file->size()), false); - } - - if (m_parser_state->gsf_input == nullptr) { - throw std::runtime_error("gsf_input_stdio_new failed"); - } - - open(); -} - -void WvWareLegacyMicrosoftFile::open() { - wvInit(); - - int ret = wvInitParser_gsf(&m_parser_state->ps, m_parser_state->gsf_input); - - m_file_meta.type = FileType::legacy_word_document; - m_file_meta.mimetype = "application/msword"; - m_file_meta.document_meta = DocumentMeta(); - m_file_meta.document_meta->document_type = DocumentType::text; - - // check if encrypted - if ((ret & 0x8000) != 0) { - m_file_meta.password_encrypted = true; - m_encryption_state = EncryptionState::encrypted; - m_parser_state->encryption_flag = ret & 0x7fff; - - if (m_parser_state->encryption_flag == WORD8 || - m_parser_state->encryption_flag == WORD7 || - m_parser_state->encryption_flag == WORD6) { - ret = 0; - } - } else { - m_encryption_state = EncryptionState::not_encrypted; - } - - if (ret != 0) { - throw std::runtime_error("wvInitParser failed"); - } -} - -std::shared_ptr -WvWareLegacyMicrosoftFile::file() const noexcept { - return m_file; -} - -DecoderEngine WvWareLegacyMicrosoftFile::decoder_engine() const noexcept { - return DecoderEngine::wvware; -} - -FileType WvWareLegacyMicrosoftFile::file_type() const noexcept { - return FileType::legacy_word_document; -} - -std::string_view WvWareLegacyMicrosoftFile::mimetype() const noexcept { - return "application/msword"; -} - -FileMeta WvWareLegacyMicrosoftFile::file_meta() const noexcept { - return m_file_meta; -} - -DocumentType WvWareLegacyMicrosoftFile::document_type() const { - return DocumentType::text; -} - -DocumentMeta WvWareLegacyMicrosoftFile::document_meta() const { - // document_meta is always set for document files - // NOLINTNEXTLINE(bugprone-unchecked-optional-access) - return m_file_meta.document_meta.value(); -} - -bool WvWareLegacyMicrosoftFile::password_encrypted() const noexcept { - return m_file_meta.password_encrypted; -} - -EncryptionState WvWareLegacyMicrosoftFile::encryption_state() const noexcept { - return m_encryption_state; -} - -std::shared_ptr -WvWareLegacyMicrosoftFile::decrypt(const std::string &password) const { - if (m_encryption_state != EncryptionState::encrypted) { - throw NotEncryptedError(); - } - - wvSetPassword(password.c_str(), &m_parser_state->ps); - - bool success = false; - - if (m_parser_state->encryption_flag == WORD8) { - success = wvDecrypt97(&m_parser_state->ps) == 0; - } else if (m_parser_state->encryption_flag == WORD7 || - m_parser_state->encryption_flag == WORD6) { - success = wvDecrypt95(&m_parser_state->ps) == 0; - } - - if (!success) { - throw WrongPasswordError(); - } - - auto decrypted = std::make_shared(*this); - decrypted->m_encryption_state = EncryptionState::decrypted; - return decrypted; -} - -bool WvWareLegacyMicrosoftFile::is_decodable() const noexcept { return false; } - -std::shared_ptr -WvWareLegacyMicrosoftFile::document() const { - throw UnsupportedFileEncoding("generally unsupported"); -} - -wvParseStruct &WvWareLegacyMicrosoftFile::parse_struct() const { - return m_parser_state->ps; -} - -} // namespace odr::internal diff --git a/src/odr/internal/oldms_wvware/wvware_oldms_file.hpp b/src/odr/internal/oldms_wvware/wvware_oldms_file.hpp deleted file mode 100644 index aab3bed2f..000000000 --- a/src/odr/internal/oldms_wvware/wvware_oldms_file.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include - -#include - -#include - -// NOLINTNEXTLINE(bugprone-reserved-identifier) - wvware's own (C) struct name -struct _wvParseStruct; -using wvParseStruct = - struct _wvParseStruct; // NOLINT(bugprone-reserved-identifier) - -namespace odr::internal { - -class WvWareLegacyMicrosoftFile final : public abstract::DocumentFile { -public: - explicit WvWareLegacyMicrosoftFile(std::shared_ptr file); - - [[nodiscard]] std::shared_ptr file() const noexcept override; - - [[nodiscard]] DecoderEngine decoder_engine() const noexcept override; - [[nodiscard]] FileType file_type() const noexcept override; - [[nodiscard]] std::string_view mimetype() const noexcept override; - [[nodiscard]] FileMeta file_meta() const noexcept override; - - [[nodiscard]] DocumentType document_type() const override; - [[nodiscard]] DocumentMeta document_meta() const override; - - [[nodiscard]] bool password_encrypted() const noexcept override; - [[nodiscard]] EncryptionState encryption_state() const noexcept override; - [[nodiscard]] std::shared_ptr - decrypt(const std::string &password) const override; - - [[nodiscard]] bool is_decodable() const noexcept override; - - [[nodiscard]] std::shared_ptr document() const override; - - [[nodiscard]] wvParseStruct &parse_struct() const; - -private: - struct ParserState; - - std::shared_ptr m_file; - std::shared_ptr m_parser_state; - - FileMeta m_file_meta; - EncryptionState m_encryption_state{EncryptionState::unknown}; - - void open(); -}; - -} // namespace odr::internal diff --git a/src/odr/internal/open_strategy.cpp b/src/odr/internal/open_strategy.cpp index 32f3dabb7..00e5b8be3 100644 --- a/src/odr/internal/open_strategy.cpp +++ b/src/odr/internal/open_strategy.cpp @@ -15,10 +15,8 @@ #include #include #include -#include #include #include -#include #include #include @@ -131,26 +129,6 @@ open_strategy::list_file_types(const std::shared_ptr &file, } catch (...) { ODR_VERBOSE(logger, "failed to open as text"); } - - // some pdf files are weird -#ifdef ODR_WITH_PDF2HTMLEX - try { - ODR_VERBOSE(logger, "try open as pdf with poppler"); - result.push_back(PopplerPdfFile(file).file_type()); - } catch (...) { - ODR_VERBOSE(logger, "failed to open as pdf with poppler"); - } -#endif - - // just to be sure we don't miss any legacy ms files -#ifdef ODR_WITH_WVWARE - try { - ODR_VERBOSE(logger, "try open as legacy ms with wvware"); - result.push_back(WvWareLegacyMicrosoftFile(file).file_type()); - } catch (...) { - ODR_VERBOSE(logger, "failed to open as legacy ms with wvware"); - } -#endif } else { ODR_VERBOSE(logger, "anything else"); result.push_back(file_type); @@ -159,20 +137,11 @@ open_strategy::list_file_types(const std::shared_ptr &file, return result; } -std::vector -open_strategy::list_decoder_engines(const FileType as) { +std::vector open_strategy::list_decoder_engines(const FileType) { std::vector result; result.push_back(DecoderEngine::odr); - if (as == FileType::legacy_word_document) { - result.push_back(DecoderEngine::wvware); - } - - if (as == FileType::portable_document_format) { - result.push_back(DecoderEngine::poppler); - } - return result; } @@ -277,16 +246,6 @@ open_strategy::open_file(const std::shared_ptr &file, ODR_VERBOSE(logger, "failed to open as text"); } - // some pdf files are weird -#ifdef ODR_WITH_PDF2HTMLEX - try { - ODR_VERBOSE(logger, "try open as pdf with poppler"); - return std::make_unique(file); - } catch (...) { - ODR_VERBOSE(logger, "failed to open as pdf with poppler"); - } -#endif - ODR_ERROR(logger, "unknown file type"); throw UnknownFileType(); } @@ -370,17 +329,6 @@ open_strategy::open_file(const std::shared_ptr &file, } throw NoLegacyMicrosoftFile(); } -#ifdef ODR_WITH_WVWARE - if (with == DecoderEngine::wvware) { - ODR_VERBOSE(logger, "using wvware engine"); - try { - return std::make_unique(file); - } catch (...) { - ODR_VERBOSE(logger, "failed to open as legacy ms with wvware engine"); - } - throw NoLegacyMicrosoftFile(); - } -#endif ODR_ERROR(logger, "unsupported decoder engine for legacy ms " << decoder_engine_to_string(with)); throw UnsupportedDecoderEngine(with); @@ -397,17 +345,6 @@ open_strategy::open_file(const std::shared_ptr &file, } throw NoPdfFile(); } -#ifdef ODR_WITH_PDF2HTMLEX - if (with == DecoderEngine::poppler) { - ODR_VERBOSE(logger, "using poppler engine"); - try { - return std::make_unique(file); - } catch (...) { - ODR_VERBOSE(logger, "failed to open as pdf with poppler engine"); - } - throw NoPdfFile(); - } -#endif ODR_ERROR(logger, "unsupported decoder engine for pdf " << decoder_engine_to_string(with)); throw UnsupportedDecoderEngine(with); diff --git a/src/odr/internal/pdf/AGENTS.md b/src/odr/internal/pdf/AGENTS.md index 9074ee320..c515e3bda 100644 --- a/src/odr/internal/pdf/AGENTS.md +++ b/src/odr/internal/pdf/AGENTS.md @@ -4,15 +4,12 @@ The **why** behind the `pdf/` module and the roadmap. What is concretely implemented is in the code; this file keeps the rationale, the non-obvious invariants, and where things live. Reference links live in [`README.md`](README.md). -This is the `DecoderEngine::odr` path for PDF. The sibling `../pdf_poppler/` -module (poppler / pdf2htmlEX, behind `ODR_WITH_PDF2HTMLEX`) is the -production-quality alternative engine; this one is experimental. +This is the only PDF path; `DecoderEngine::odr` is the only engine. **Goal.** Faithful read-only HTML for common real-world PDFs through a -pure-serialization pipeline (no native renderer), so the poppler engine becomes -optional rather than required. The file-format, text-extraction, font and -graphics foundations are in place; what remains is interaction & navigation plus -a tail of known gaps (see *Roadmap*). +pure-serialization pipeline (no native renderer). The file-format, +text-extraction, font and graphics foundations are in place; what remains is +interaction & navigation plus a tail of known gaps (see *Roadmap*). **Scope in one line.** Parse the PDF object/file structure (xref tables, xref streams, object streams, hybrid files, forward-scan recovery), decrypt (RC4, @@ -216,9 +213,7 @@ Consumers outside the module: `open_strategy.cpp` (detection/engine selection) a `sfnt_*`, `cff_*`, `type1_*`). The **reference-output snapshot test** (`test/data/reference-output/`) is the -graphics oracle: each change regenerates it and the diff is reviewed. It is now -the **odr engine's own output only** — the `*.pdf-poppler` / `*.doc-wvware` -cross-engine snapshots were removed once the odr engine could replace them. +graphics oracle: each change regenerates it and the diff is reviewed. --- diff --git a/src/odr/internal/pdf_poppler/poppler_pdf_file.cpp b/src/odr/internal/pdf_poppler/poppler_pdf_file.cpp deleted file mode 100644 index e5a4c7a61..000000000 --- a/src/odr/internal/pdf_poppler/poppler_pdf_file.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include - -#include - -#include -#include -#include - -namespace odr::internal { - -PopplerPdfFile::PopplerPdfFile(std::shared_ptr file) - : m_file{std::move(file)} { - open(std::nullopt); -} - -void PopplerPdfFile::open(const std::optional &password) { - std::optional password_goo; - if (password.has_value()) { - password_goo = GooString(password.value().c_str()); - } - - if (const std::shared_ptr disk_file = - std::dynamic_pointer_cast(m_file); - disk_file != nullptr) { - // NOLINTNEXTLINE(bugprone-unchecked-optional-access): a DiskFile has a path - auto file_path_goo = - std::make_unique(disk_file->disk_path()->string().c_str()); - m_pdf_doc = std::make_shared(std::move(file_path_goo), password_goo, - password_goo); - } else if (const std::shared_ptr memory_file = - std::dynamic_pointer_cast(m_file); - memory_file != nullptr) { - auto stream = std::make_unique( - memory_file->memory_data(), 0, - static_cast(memory_file->size()), Object::null()); - m_pdf_doc = - std::make_shared(std::move(stream), password_goo, password_goo); - } else { - throw NoPdfFile(); - } - - if (!m_pdf_doc->isOk()) { - if (m_pdf_doc->getErrorCode() == errEncrypted) { - m_encryption_state = EncryptionState::encrypted; - } else { - throw std::runtime_error("Failed to open PDF file"); - } - } else { - m_encryption_state = m_pdf_doc->isEncrypted() - ? EncryptionState::decrypted - : EncryptionState::not_encrypted; - } - - m_file_meta.type = FileType::portable_document_format; - m_file_meta.mimetype = "application/pdf"; - // for some reason `isEncrypted` can return `true` even if the file is opened - // without password - m_file_meta.password_encrypted = - m_encryption_state == EncryptionState::encrypted || - (password_goo.has_value() && m_pdf_doc->isEncrypted()); - m_file_meta.document_meta.emplace(); - m_file_meta.document_meta->document_type = DocumentType::text; - if (m_encryption_state != EncryptionState::encrypted) { - m_file_meta.document_meta->entry_count = m_pdf_doc->getNumPages(); - } -} - -std::shared_ptr PopplerPdfFile::file() const noexcept { - return m_file; -} - -DecoderEngine PopplerPdfFile::decoder_engine() const noexcept { - return DecoderEngine::poppler; -} - -FileMeta PopplerPdfFile::file_meta() const noexcept { return m_file_meta; } - -bool PopplerPdfFile::password_encrypted() const noexcept { - return m_file_meta.password_encrypted; -} - -EncryptionState PopplerPdfFile::encryption_state() const noexcept { - return m_encryption_state; -} - -std::shared_ptr -PopplerPdfFile::decrypt(const std::string &password) const { - if (encryption_state() != EncryptionState::encrypted) { - throw NotEncryptedError(); - } - - auto decrypted_file = std::make_shared(*this); - try { - decrypted_file->open(password); - } catch (const std::exception &) { - throw DecryptionFailed(); - } - if (decrypted_file->encryption_state() != EncryptionState::decrypted) { - throw WrongPasswordError(); - } - return decrypted_file; -} - -bool PopplerPdfFile::is_decodable() const noexcept { return false; } - -PDFDoc &PopplerPdfFile::pdf_doc() const { return *m_pdf_doc; } - -} // namespace odr::internal diff --git a/src/odr/internal/pdf_poppler/poppler_pdf_file.hpp b/src/odr/internal/pdf_poppler/poppler_pdf_file.hpp deleted file mode 100644 index 39c79ffec..000000000 --- a/src/odr/internal/pdf_poppler/poppler_pdf_file.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include - -#include - -class PDFDoc; - -namespace odr::internal { - -class PopplerPdfFile final : public abstract::PdfFile { -public: - explicit PopplerPdfFile(std::shared_ptr file); - - [[nodiscard]] std::shared_ptr file() const noexcept override; - - [[nodiscard]] DecoderEngine decoder_engine() const noexcept override; - [[nodiscard]] FileMeta file_meta() const noexcept override; - - [[nodiscard]] bool password_encrypted() const noexcept override; - [[nodiscard]] EncryptionState encryption_state() const noexcept override; - [[nodiscard]] std::shared_ptr - decrypt(const std::string &password) const override; - - [[nodiscard]] bool is_decodable() const noexcept override; - - [[nodiscard]] PDFDoc &pdf_doc() const; - -private: - std::shared_ptr m_file; - std::shared_ptr m_pdf_doc; - - EncryptionState m_encryption_state{EncryptionState::unknown}; - FileMeta m_file_meta; - - void open(const std::optional &password); -}; - -} // namespace odr::internal diff --git a/src/odr/internal/project_info.cpp.in b/src/odr/internal/project_info.cpp.in index 7c9d0ca48..9b463e284 100644 --- a/src/odr/internal/project_info.cpp.in +++ b/src/odr/internal/project_info.cpp.in @@ -14,22 +14,6 @@ bool project_info::is_debug() noexcept { #endif } -bool project_info::has_wvware() noexcept { -#ifdef ODR_WITH_WVWARE - return true; -#else - return false; -#endif -} - -bool project_info::has_pdf2htmlex() noexcept { -#ifdef ODR_WITH_PDF2HTMLEX - return true; -#else - return false; -#endif -} - bool project_info::has_libmagic() noexcept { #ifdef ODR_WITH_LIBMAGIC return true; @@ -42,18 +26,6 @@ const char *project_info::odr_data_path() noexcept { return "${ODR_INSTALL_ODR_DATA_PATH}"; } -const char *project_info::fontconfig_data_path() noexcept { - return "${ODR_INSTALL_FONTCONFIG_DATA_PATH}"; -} - -const char *project_info::poppler_data_path() noexcept { - return "${ODR_INSTALL_POPPLER_DATA_PATH}"; -} - -const char *project_info::pdf2htmlex_data_path() noexcept { - return "${ODR_INSTALL_PDF2HTMLEX_DATA_PATH}"; -} - const char *project_info::libmagic_database_path() noexcept { return "${ODR_INSTALL_LIBMAGIC_DATABASE_PATH}"; } diff --git a/src/odr/internal/project_info.hpp b/src/odr/internal/project_info.hpp index e743ffc59..a99cc7bb4 100644 --- a/src/odr/internal/project_info.hpp +++ b/src/odr/internal/project_info.hpp @@ -5,14 +5,9 @@ namespace odr::internal::project_info { const char *version() noexcept; bool is_debug() noexcept; -bool has_wvware() noexcept; -bool has_pdf2htmlex() noexcept; bool has_libmagic() noexcept; const char *odr_data_path() noexcept; -const char *fontconfig_data_path() noexcept; -const char *poppler_data_path() noexcept; -const char *pdf2htmlex_data_path() noexcept; const char *libmagic_database_path() noexcept; } // namespace odr::internal::project_info diff --git a/src/odr/odr.cpp b/src/odr/odr.cpp index 07eac9747..85071c076 100644 --- a/src/odr/odr.cpp +++ b/src/odr/odr.cpp @@ -419,12 +419,6 @@ std::string odr::decoder_engine_to_string(const DecoderEngine engine) { if (engine == DecoderEngine::odr) { return "odr"; } - if (engine == DecoderEngine::poppler) { - return "poppler"; - } - if (engine == DecoderEngine::wvware) { - return "wvware"; - } throw UnknownDecoderEngine(); } @@ -432,12 +426,6 @@ odr::DecoderEngine odr::decoder_engine_by_name(const std::string &engine) { if (engine == "odr") { return DecoderEngine::odr; } - if (engine == "poppler") { - return DecoderEngine::poppler; - } - if (engine == "wvware") { - return DecoderEngine::wvware; - } throw UnknownDecoderEngine(); } diff --git a/test/src/html_output_test.cpp b/test/src/html_output_test.cpp index 1891c0178..8b897f0e3 100644 --- a/test/src/html_output_test.cpp +++ b/test/src/html_output_test.cpp @@ -111,13 +111,6 @@ TEST_P(HtmlOutputTests, html_meta) { GTEST_SKIP(); } - // TODO wvware decryption - if (test_file.password.has_value() && - test_file.type == FileType::legacy_word_document && - engine == DecoderEngine::wvware) { - GTEST_SKIP(); - } - // TODO oldms decryption if (test_file.password.has_value() && test_file.type == FileType::legacy_word_document && @@ -200,7 +193,7 @@ std::string engine_suffix(const DecoderEngine engine) { /// The default `dual_layer` mode carries no suffix so existing (non-PDF and /// dual-layer) reference outputs keep their paths; single-layer variants are -/// disambiguated with `-single`, mirroring the `-poppler` engine suffix. +/// disambiguated with `-single`. std::string text_mode_suffix(const PdfTextMode pdf_text_mode) { return pdf_text_mode == PdfTextMode::dual_layer ? "" : "-single"; } diff --git a/test/src/test_info.cpp.in b/test/src/test_info.cpp.in index 44274ef79..0653221b6 100644 --- a/test/src/test_info.cpp.in +++ b/test/src/test_info.cpp.in @@ -6,18 +6,6 @@ const char *info::odr_data_path() noexcept { return "${ODR_BUILD_ODR_DATA_PATH}"; } -const char *info::fontconfig_data_path() noexcept { - return "${ODR_BUILD_FONTCONFIG_DATA_PATH}"; -} - -const char *info::poppler_data_path() noexcept { - return "${ODR_BUILD_POPPLER_DATA_PATH}"; -} - -const char *info::pdf2htmlex_data_path() noexcept { - return "${ODR_BUILD_PDF2HTMLEX_DATA_PATH}"; -} - const char *info::libmagic_database_path() noexcept { return "${ODR_BUILD_LIBMAGIC_DATABASE_PATH}"; } diff --git a/test/src/test_info.hpp b/test/src/test_info.hpp index d2f8b198f..8f5d89d3b 100644 --- a/test/src/test_info.hpp +++ b/test/src/test_info.hpp @@ -3,9 +3,6 @@ namespace odr::test::info { const char *odr_data_path() noexcept; -const char *fontconfig_data_path() noexcept; -const char *poppler_data_path() noexcept; -const char *pdf2htmlex_data_path() noexcept; const char *libmagic_database_path() noexcept; const char *odr_test_data_path() noexcept; diff --git a/test/src/test_util.cpp b/test/src/test_util.cpp index ec5e37d04..f9bc53007 100644 --- a/test/src/test_util.cpp +++ b/test/src/test_util.cpp @@ -23,9 +23,6 @@ namespace odr { void test::set_global_params() { GlobalParams::set_odr_core_data_path(info::odr_data_path()); - GlobalParams::set_fontconfig_data_path(info::fontconfig_data_path()); - GlobalParams::set_poppler_data_path(info::poppler_data_path()); - GlobalParams::set_pdf2htmlex_data_path(info::pdf2htmlex_data_path()); GlobalParams::set_libmagic_database_path(info::libmagic_database_path()); }